某个类作了应该由两个类作的事。创建一个新类,将相关字段和函数从旧类搬移到新类。 java
咱们都知道,一个类应该是一个清楚的抽象,处理一些明确的责任,可是在实际工做中,类会不断成长扩展,随着责任不断增长,这个类会变得过度复杂。若是某些数据和某些函数老是一块儿出现,某些数据常常同时变化甚至彼此相依,这就表示应该将它们分离出去。一个有用的测试就是问本身,若是搬移了某些字段和函数,会发生什么事?其余字段和函数是否所以变得无心义? 程序员
另外一个每每在开发后期出现的信号是类的子类化方式。若是你发现子类化只影响类的部分特性,或若是你发现某些特性须要以一种方式来子类化,某些特性则须要以另外一种方式子类化,这就意味着你须要分解原来的类。 并发
1.决定如何分解类所负的责任。 函数
2.创建一个新类,用以表现从旧类中分离出来的责任。 测试
若是旧类剩下的责任与旧类名不符,为旧类改名 spa
3.创建“从旧类访问新类”的连接关系 code
有可能须要一个双向连接。可是在真正须要它以前,不要创建“重新类通往旧类”的连接 对象
4.对于想搬移的没一个字段,运用Move Field 搬移之。 接口
5.每次搬移后,编译、测试。 事务
6. 使用Move Method将必要函数搬移到新类。先搬移较低层函数(“被其余函数调用”多于“调用其余函数”者),再搬移较高层函数。
7.每次搬移以后,编译、测试
8. 检查,精简每一个类的接口
若是创建起双向链接,检查是否能够将它改成单向链接。
9决定是否公开新类。若是的确须要公开它,就要决定让它成为引用对象仍是不可变的值对象。
咱们从一个简单的person类开始
public class Person { private String name; private String officeAreaCode; private String officeNumber; public String getName() { return name; } public String getTelephoneNumber() { return ( "(" + officeAreaCode + ")" + officeNumber ); } public String getOfficeAreaCode() { return officeAreaCode; } public void setOfficeAreaCode( String arg ) { officeAreaCode = arg; } public String getOfficeNumber() { return officeNumber; } public void setOfficeNumber( String arg ) { officeNumber = arg; } }在这个例子中,咱们能够将与电话号码相关的行为分离到一个独立类中。首先要定义一个TelephoneNumber类来表示“电话号码”这个概念
public class TelephoneNumber { }而后,创建从Person到TelephoneNumber的连接:
public class Person { private TelephoneNumber officeTelephone = new TelephoneNumber(); ... }
如今,咱们运用Move Field移动一个字段:
public class TelephoneNumber { private String areaCode; String getAreaCode() { return areaCode; } void setAreaCode( String arg ) { areaCode = arg; } }
public class Person { public String getTelephoneNumber() { return ( "(" + getOfficeAreaCode() + ")" + officeNumber ); } public String getOfficeAreaCode() { return officeTelephone.getAreaCode(); } public void setOfficeAreaCode( String arg ) { officeTelephone.setAreaCode( arg ); }
而后咱们能够移动其余字段,并运用Move Method将相关函数移动到TelephoneNumber类中:
public class TelephoneNumber { private String areaCode; private String number; public String getTelephnoeNumber() { return ( "(" + getAreaCode() + ")" + number ); } String getAreaCode() { return areaCode; } void setAreaCode( String arg ) { areaCode = arg; } String getNumber() { return number; } void setNumber( String arg ) { number = arg; } }
public class Person { private TelephoneNumber officeTelephone = new TelephoneNumber(); private String name; public String getName() { return name; } public String getTelephoneNumber() { return officeTelephone.getTelephnoeNumber(); } TelephoneNumber getOfficeTelephone() { return officeTelephone; } }下一步要作的决定是:要不要对用户公开这个新类? 咱们能够将Person中与电话号码相关的函数委托至TelephoneNumber,从而彻底隐藏这个新类;也能够直接将它对用户公开。咱们还能够将它公开给部分用户。
若是选择公开新类,就须要考虑别名带来的危险。若是公开了TelephoneNumber,而有个用户修改了对象中的areaCode字段值,咱们又怎么能知道呢?并且,作出修改的可能不是直接用户,而是用户的用户。
面对这个问题,咱们又下列几种选择。
1.容许任何对象修改TelephoneNumber对象的任何部分。这就使得TelephoneNumber对象成为引用对象,因而咱们应该考虑使用Change Value to Reference。这种状况下,Person应该是TelephoneNumber的访问点。
2.不容许任何人不经过Person对象就修改TelephoneNumber对象。为此,咱们能够将TelephoneNumber设为不可修改的,或为它提供一个不可修改的接口。
3. 另外一个办法是:先复制一个TelephoneNumber对象,而后将复制获得的新对象传递给用户。但这可能会形成必定程度的迷惑,由于人们会认为他们能够修改TelephoneNumber对象值。此外,若是同一个TelephoneNumber对象被传递给多个用户,也可能在用户之间形成别名问题。
Extract Class是改善并发程序的一种经常使用技术,由于它使你能够为提炼后的两个类分别加锁。若是你不须要同时锁定两个对象,就没必要这样作。
这里也存在危险性。若是须要确保两个对象被同时锁定,就面临事务问题,须要使用其余类型的共享锁。这是一个复杂的领域,比起通常状况须要更繁重的机制。事务颇有实用性,可是编写事务管理程序则超出了大多数程序员的职责范围。