重构手法之在对象之间搬移特性【2】
本小节目录
3Extract Class(提炼类)
概要
某个类做了应该由两个类做的事。
建立一个新类,将相关的字段和函数从旧类搬移到新类。
动机
如果一个类中有大量的函数和数据,这个类往往太大而且不易理解。这时候就需要考虑哪些部分可以分离出去,并将它们分离到一个单独的类中。
如果发现子类化只影响类的部分特性,或如果某些特性需要以一种方式来子类化,某些特性则需要以另一种方式子类化,这也意味着需要分解原来的类。
范例
先看一个简单的Person类。
class Person { public string Name { get; set; } public string OfficeAreaCode { get; set; } public string OfficeNumber { get; set; } public string GetTelephoneNumber() { return $"({OfficeAreaCode})-{OfficeNumber}"; } }
在这里,我们可以将与电话号码有关的行为分离到一个独立的类中。
首先,定义一个TelePhoneNumber类表示“电话号码”:
class TelePhoneNumber{}
然后,在Person类中建立从Person到TelePhoneNumber的连接:
private TelePhoneNumber _phoneNumber = new TelePhoneNumber();
现在运用Move Field移动属性,并运用Move Method将相关函数移动到TelePhoneNumber类中。
class Person { private TelePhoneNumber _phoneNumber = new TelePhoneNumber(); public string Name { get; set; } public string GetTelephoneNumber() { return _phoneNumber.GetTelephoneNumber(); } }
class TelePhoneNumber { public string OfficeAreaCode { get; set; } public string OfficeNumber { get; set; } public string GetTelephoneNumber() { return $"({OfficeAreaCode})-{OfficeNumber}"; } }
小结
类的单一原则表示:一个类应该是一个清楚的抽象,处理一些明确的责任。如果一个类做了两个类的事,那它就该被提炼了。
4Inline Class(将类内联化)
概要
某个类没有做太多事情。
将这个类的所有特性搬移到另一个类中,然后移除原类。
动机
Inline Class和Extract Class正好相反。如果一个类不再承担足够责任、不再有单独存在的理由,那么就将其塞进另一个类中。
范例
第3节中我们提炼出一个TelePhoneNumber类,现在我们将其塞回Person中。
class Person { private TelePhoneNumber _phoneNumber = new TelePhoneNumber(); public string Name { get; set; } public string GetTelephoneNumber() { return _phoneNumber.GetTelephoneNumber(); } } class TelePhoneNumber { public string OfficeAreaCode { get; set; } public string OfficeNumber { get; set; } public string GetTelephoneNumber() { return $"({OfficeAreaCode})-{OfficeNumber}"; } }
首先,在Person中声明TelePhoneNumber的所有public的函数。
class Person { private TelePhoneNumber _phoneNumber = new TelePhoneNumber(); public string Name { get; set; } public string OfficeAreaCode { get; set; } public string OfficeNumber { get; set; } public string GetTelephoneNumber() { return _phoneNumber.GetTelephoneNumber(); } public TelePhoneNumber GetOfficeTelePhoneNumber() { return _phoneNumber; } }
现在,我们要做的就是:找出所有使用TelePhoneNumber的地方,让它们使用Person的接口。于是,下列代码:
Person martin=new Person(); martin.GetOfficeTelePhoneNumber().OfficeAreaCode = "781";
就变成了:
Person martin=new Person(); martin.OfficeAreaCode = "781";
最后,反复使用Move Method和Move Field,直到TelePhoneNumber类不复存在。
小结
如果一个类无所事事,那么这就是一种坏味道——Lazy Class。遇到这种类,我们应该毫不犹豫的为它举行“葬礼”,将它塞进其他类中。
To Be Continued……