Sco*_*ipp 12 java oop law-of-demeter
我已阅读几乎所有标记为Demeter法的问题.我的具体问题在任何其他问题中都没有得到回答,尽管它非常相似.主要是我的问题是当你有一个具有复合层的对象,但需要从各种对象中检索属性值时,你如何实现这一点以及为什么采用一种方法而不是另一种?
假设你有一个非常标准的对象,由其他对象组成,如下所示:
public class Customer {
private String name;
private ContactInfo primaryAddress;
private ContactInfo workAddress;
private Interests hobbies;
//Etc...
public getPrimaryAddress() { return primaryAddress; }
public getWorkAddress() { return workAddress; }
public getHobbies() { return hobbies; }
//Etc...
}
private ContactInfo {
private String phoneNumber;
private String emailAddress;
//Etc...
public getPhoneNumber() { return phoneNumber; }
public getEmailAddress() { return emailAddress; }
//Etc...
}
private Interests {
private List listOfInterests;
}
Run Code Online (Sandbox Code Playgroud)
以下都违反了得墨忒耳法则:
System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber());
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString());
Run Code Online (Sandbox Code Playgroud)
我认为这也违反了得墨忒耳法(澄清?):
ContactInfo customerPrimaryAddress = customer.getPrimaryAddress();
System.out.println("Phone: " + customerPrimaryAddress.getPhoneNumber());
Run Code Online (Sandbox Code Playgroud)
因此,假设您将向客户添加"getPrimaryPhoneNumber()"方法:
public getPrimaryPhoneNumber() {
return primaryAddress.getPhoneNumber();
}
Run Code Online (Sandbox Code Playgroud)
然后简单地调用:System.out.println("Phone:"+ customer.getPrimaryPhoneNumber());
但是,随着时间的推移这样做似乎实际上会提供很多问题,并违背了得墨忒耳法的意图.它使Customer类变成了一大堆getter和setter,它们对自己的内部类有太多的了解.例如,有一天Customer对象可能有各种地址(不仅仅是"主要"和"工作"地址).甚至Customer类也可能只有一个List(或其他集合)的ContactInfo对象,而不是特定的命名ContactInfo对象.在这种情况下,你如何继续遵守得墨忒耳定律?它似乎打败了抽象的目的.例如,在客户拥有ContactInfo项列表的情况下,这似乎是合理的:
Customer.getSomeParticularAddress(addressType).getPhoneNumber();
Run Code Online (Sandbox Code Playgroud)
当你想到有些人拥有移动电话和固定电话时,这似乎会变得更加疯狂,然后ContactInfo必须拥有一组电话号码.
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们不仅引用对象内对象内的对象,而且还必须知道有效的addressType和phoneType是什么.我肯定能看到这个问题,但我不确定如何避免它.特别是当任何一个班级打电话给他们时,可能知道他们想要为相关客户的"主要"地址提取"移动"电话号码.
如何重构以符合德米特定律,为什么这样做会好?
根据我的经验,Customer显示的示例不是由其他对象 \xe2\x80\x9d 组成的 \xe2\x80\x9c 标准对象,因为此示例采取了将其组成部分实现为内部类的附加步骤,并进一步将这些内部类私人的。\xe2\x80\x99s 并不是一件坏事。
一般来说,私有访问修饰符会增加信息隐藏,这是德米特定律的基础。暴露私有类是矛盾的。NetBeans IDE 实际上包含一个默认编译器警告:\xe2\x80\x9c通过公共 API\xe2\x80\x9d 导出非公共类型。
\n\n我断言,将私有类暴露在其封闭类之外总是不好的:它减少了信息隐藏并违反了德米特法则。ContactInfo因此,要回答有关返回外部实例的澄清问题Customer:是的,这是违规的。
getPrimaryPhoneNumber()建议的添加方法的解决方案Customer是一个有效的选择。混乱就在这里: \xe2\x80\x9cCustomer...对其自己的内部类有太多的了解。\xe2\x80\x9d 那\xe2\x80\x99s 是不可能的;这就是为什么这个示例不是标准组合示例很重要。
封闭类对任何嵌套类都有 100% 的了解。总是。无论这些嵌套类在封闭类(或其他任何地方)中如何使用。这就是为什么封闭类可以直接访问其嵌套类的私有字段和方法:封闭类本质上知道它们的一切,因为它们是在其中实现的。
\n\n给定类 Foo 的荒谬示例,该类有一个嵌套类 Bar,该类有一个嵌套类 Baz,该类有一个嵌套类 Qux,对于 Foo(内部)调用 bar.baz.qux 不会违反 Demeter 。方法()。Foo 已经了解了有关 Bar、Baz 和 Qux 的所有信息;因为他们的代码位于 Foo 内部,所以没有通过长方法链传递额外的知识。
\n\n根据德米特定律,解决方案是Customer不返回中间对象,无论其内部实现如何;即,无论Customer是使用多个嵌套类还是不使用任何嵌套类来实现,它都应该只返回其客户端类最终需要的内容。
例如,最后一个代码片段可能会重构为,\ncustomer.getPhoneNumber(addressType, phoneType);
或者如果只有少量选项,\ncustomer.getPrimaryMobilePhoneNumber();
这两种方法都会导致类的用户Customer不知道其内部实现,并确保这些用户不必通过他们不直接感兴趣的对象进行调用。
| 归档时间: |
|
| 查看次数: |
1046 次 |
| 最近记录: |