Java 德米特定律和构图与收藏品是如何协同工作的?
我已经阅读了几乎所有的题为德墨忒尔定律的问题。我的具体问题在其他任何问题中都没有得到回答,尽管它非常相似。我的主要问题是,当您有一个具有组成层的对象,但需要从各种对象检索属性值时,如何实现这一点,以及为什么要采用一种方法而不是另一种方法 假设您有一个由其他对象组成的非常标准的对象,如下所示:Java 德米特定律和构图与收藏品是如何协同工作的?,java,oop,law-of-demeter,Java,Oop,Law Of Demeter,我已经阅读了几乎所有的题为德墨忒尔定律的问题。我的具体问题在其他任何问题中都没有得到回答,尽管它非常相似。我的主要问题是,当您有一个具有组成层的对象,但需要从各种对象检索属性值时,如何实现这一点,以及为什么要采用一种方法而不是另一种方法 假设您有一个由其他对象组成的非常标准的对象,如下所示: public class Customer { private String name; private ContactInfo primaryAddress; private ContactI
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;
}
以下两项都将违反德米特法:
System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber());
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString());
我认为这也违反了德米特法(澄清?):
因此,您可能会向Customer添加一个“getPrimaryPhoneNumber()”方法:
public getPrimaryPhoneNumber() {
return primaryAddress.getPhoneNumber();
}
然后简单地打电话:
System.out.println(“电话:+customer.getPrimaryPhoneNumber())
但随着时间的推移,这样做似乎会带来很多问题,并违背了德米特法的意图。它将Customer类变成了一个巨大的getter和setter包,这些getter和setter对其内部类有太多的了解。例如,客户对象可能有一天会有不同的地址(不仅仅是“主”和“工作”地址)。也许甚至Customer类也只是拥有ContactInfo对象的列表(或其他集合),而不是特定的命名ContactInfo对象。在这种情况下,你如何继续遵循德米特定律?这似乎违背了抽象的目的。例如,在客户拥有ContactInfo项目列表的情况下,这似乎是合理的:
Customer.getSomeParticularAddress(addressType).getPhoneNumber();
当你想到有些人有一部手机和一部固定电话,然后ContactInfo必须有一组电话号码时,这似乎会变得更疯狂
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
在这种情况下,我们不仅要在对象中的对象中引用对象,还要知道有效的addressType和phoneType是什么。我可以肯定地看到这是一个问题,但我不知道如何避免它。特别是当任何一个班级打电话时,他们可能都知道他们想把“移动”电话号码拨到客户的“主要”地址
如何对其进行重构以符合Demeter定律?为什么这样做很好?根据我的经验,所示的
客户
示例不是“由其他对象组成的标准对象”,因为该示例采用了将其组成部分实现为内部类的附加步骤,并进一步将这些内部阶级私有化。这不是一件坏事
一般来说,私有访问修改器增加了信息隐藏,这是Demeter法的基础。揭露私人阶级是自相矛盾的。NetBeans IDE实际上包含一个默认编译器警告,“通过公共API导出非公共类型”
我认为,将私有类暴露在其封闭类之外总是不好的:它减少了信息隐藏并违反了Demeter定律。因此,要回答有关在Customer
之外返回ContactInfo
实例的澄清问题:是的,这是一种违反
向Customer
添加getPrimaryPhoneNumber()
方法的建议解决方案是一个有效的选项。困惑就在这里:“客户……对自己的内部类了解太多了。”这是不可能的;这就是为什么这个例子不是一个标准的合成例子很重要
封闭类100%了解任何嵌套类。总是。无论这些嵌套类如何在封闭类(或其他任何地方)中使用。这就是为什么封闭类可以直接访问其嵌套类的私有字段和方法:封闭类本质上知道它们的一切,因为它们是在它内部实现的
给出了一个荒谬的例子:一个类Foo,它有一个嵌套的类Bar,它有一个嵌套的类Baz,它有一个嵌套的类Qux,Foo(内部)调用Bar.Baz.Qux.method()不会违反Demeter。富已经知道了所有关于酒吧、巴兹和曲棍球的知识;因为他们的代码在Foo中,所以没有额外的知识通过长方法链传递
然后,根据德米特定律,解决方案是Customer
不返回中间对象,无论其内部实现如何;i、 e.Customer
是否使用多个嵌套类实现,它应该只返回其客户机类最终需要的内容
例如,最后一个代码段可能被重构为,
customer.getPhoneNumber(地址类型,电话类型)代码>
或者如果只有少量的选择,
customer.getPrimaryMobilePhoneNumber()代码>
这两种方法都会导致Customer
类的用户不知道其内部实现,并确保这些用户不必通过他们不直接感兴趣的对象进行调用。制作另一个名为CustomerInformationProvider
的类怎么样。您可以将Customer
对象作为构造函数参数传递给他的新类。然后你可以在这个类中写下获取电话、地址等的所有具体方法,同时保持客户
类的整洁。重要的是要记住,德米特定律是一个指南,而不是一个实际的法律。我们需要在稍微更深的层次上检查它的目的,以确定在这里做什么是正确的
德米特定律的目的是防止外部物体接触到另一物体的内部。访问内部有两个问题:1)它提供了太多关于对象内部结构的信息,2)它还允许外部访问
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
int nameLength = myObject.getName().length()
mylist.get(0).doSomething();
public class Customer {
private class InternalContactInfo {
public ContactInfo createContactinfo() {
//creates a ContactInfo based on its own values...
}
//Etc....
}
private String name;
private InternalContactInfo primaryAddress;
//Etc...
public Contactinfo getPrimaryAddress() {
// copies the info from InternalContactInfo to a new object
return primaryAddress.createContactInfo();
}
//Etc...
}
public class ContactInfo {
// Not modifiable
private String phoneNumber;
private String emailAddress;
//Etc...
public getPhoneNumber() { return phoneNumber; }
public getEmailAddress() { return emailAddress; }
//Etc...
}