某个class做了应该由两个classes做的事
你也许听过类似这样的教诲:一个class应该是一个清楚的抽象(abstract),处理一些明确的责任。
但是在实际工作中,class会不断成长扩展。你会在这儿加入一些功能,在那儿加入一些数据。
给某个class添加一项新责任时,你会觉得不值得为这项责任分离出一个单独的class。
于是,随着责任不断増加,这个class会变得过份复杂。很快,你的class就会变成一团乱麻
让我们从一个简单的Person class开始
class Person...public String getName() {return _name;}public String getTelephoneNumber() {return ("(" + _officeAreaCode + ") " + _officeNumber);}String getOfficeAreaCode() {return _officeAreaCode;}void setOfficeAreaCode(String arg) {_officeAreaCode = arg;}String getOfficeNumber() {return _officeNumber;}void setOfficeNumber(String arg) {_officeNumber = arg;}private String _name;// 电话号码区号private String _officeAreaCode;// 电话号码private String _officeNumber;
在这个例子中,我可以将「与电话号码相关」的行为分离到一个独立class中。首 先我耍定义一个TelephoneNumber class来表示「电话号码」这个概念:
class TelephoneNumber {}
然后,我要建立从Person到TelephoneNumber的连接
class Personprivate TelephoneNumber _officeTelephone = new TelephoneNumber();
我运用Move Field 移动一个值域
// 将_areaCode属性和对应的方法移到新类class TelephoneNumber {String getAreaCode() {return _areaCode;}void setAreaCode(String arg) {_areaCode = arg;}private String _areaCode;}class Person...public String getTelephoneNumber() {return ("(" + getOfficeAreaCode() + ") " + _officeNumber);}String getOfficeAreaCode() {return _officeTelephone.getAreaCode();}void setOfficeAreaCode(String arg) {_officeTelephone.setAreaCode(arg);}
然后我可以移动其他值域,并运用Move Method 将相关函数移动到TelephoneNumber class中
class Person...public String getName() {return _name;}public String getTelephoneNumber(){return _officeTelephone.getTelephoneNumber();}TelephoneNumber getOfficeTelephone() {return _officeTelephone;}private String _name;private TelephoneNumber _officeTelephone = new TelephoneNumber();class TelephoneNumber...public String getTelephoneNumber() {return ("(" + _areaCode + ") " + _number);}String getAreaCode() {return _areaCode;}void setAreaCode(String arg) {_areaCode = arg;}String getNumber() {return _number;}void setNumber(String arg) {_number = arg;}private String _number;private String _areaCode;
下一步要做的决定是:要不要对用户公开这个新类?我可以将Person中与电话号码相关的函数委托至TelephoneNumber,从而完全隐藏这个新类;也可以直接将它对用户公开。我还可以将它公开给部分用户(位于同一个包中的用户),而不公开给其他用户。
如果我选择公开新类,就需要考虑别名带来的危险。如果我公开了Telephone-Number,而有个用户修改了对象中的_areaCode字段值,我又怎么能知道呢?而且,做出修改的可能不是直接用户,而是用户的用户的用户。
面对这个问题,我有下列几种选择。
1.允许任何对象修改TelephoneNumber
对象的任何部分。这就使得TelephoneNumber
对象成为引用对象,于是我应该考虑使用Change Value to Reference (179)。这种情况下,Person应该是TelephoneNumber的访问点。
2.不许任何人不通过Person对象就修改TelephoneNumber对象。为此,我可以将TelephoneNumber
设为不可修改的,或为它提供一个不可修改的接口。
3.另一个办法是:先复制一个TelephoneNumber
对象,然后将复制得到的新对象传递给用户。但这可能会造成一定程度的迷惑,因为人们会认为他们可以修改TelephoneNumber
对象值。此外,如果同一个TelephoneNumber对象被传递给多个用户,也可能在用户之间造成别名问题。
Extract Class (149)是改善并发程序的一种常用技术,因为它使你可以为提炼后的两个类分别加锁。如果你不需要同时锁定两个对象,就不必这样做。这方面的更多信息请看Lea[Lea]的3.3节。
这里也存在危险性。如果需要确保两个对象被同时锁定,你就面临事务问题,需要使用其他类型的共享锁。正如Lea[Lea]的8.1节所讨论的,这是一个复杂领域,比起一般情况需要更繁重的机制。事务很有实用性,但是编写事务管理程序则超出了大多数程序员的职责范围。
上一篇:详解HTTPS协议