我已经阅读了几乎所有标记为 Law-of-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;
}
以下都违反了得墨忒耳法则:
System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber());
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString());
我认为这也违反了得墨忒耳法则(澄清?):
ContactInfo customerPrimaryAddress = customer.getPrimaryAddress();
System.out.println("Phone: " + customerPrimaryAddress.getPhoneNumber());
因此,据推测,您将向 Customer 添加一个“getPrimaryPhoneNumber()”方法:
public getPrimaryPhoneNumber() {
return primaryAddress.getPhoneNumber();
}
然后简单地调用: System.out.println("Phone: " + customer.getPrimaryPhoneNumber());
但随着时间的推移,这样做似乎实际上会带来很多问题,并且违背了得墨忒耳法则的意图。它使 Customer 类变成了一个巨大的 getter 和 setter 包,它们对自己的内部类有太多的了解。例如,似乎有朝一日 Customer 对象可能会有不同的地址(不仅仅是“主要”地址和“工作”地址)。甚至 Customer 类也可能只是有一个 ContactInfo 对象的列表(或其他集合),而不是特定命名的 ContactInfo 对象。在这种情况下,你如何继续遵循得墨忒耳法则?这似乎违背了抽象的目的。例如,在客户有一个 ContactInfo 项目列表的情况下,这似乎是合理的:
Customer.getSomeParticularAddress(addressType).getPhoneNumber();
当您想到某些人拥有手机和固定电话时,这似乎会变得更加疯狂,然后 ContactInfo 必须拥有电话号码的集合。
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
在这种情况下,我们不仅指的是对象内的对象内的对象,而且我们还必须知道有效的地址类型和电话类型是什么。我绝对可以看到这个问题,但我不知道如何避免它。特别是当任何班级打电话给这个时,可能确实知道他们想要为相关客户的“主要”地址提取“移动”电话号码。
这怎么能被重构以符合得墨忒耳法则,为什么会这样呢?