让我们从维基百科开始:
更正式地说,函数的Demeter法要求对象 O 的 m 方法只能调用以下类型对象的方法:
- O本身
- m参数
- 在m
中创建/实例化的任何对象- O的直接组件对象
- 一个全局变量,可由O访问,范围为m
醇>
规则1:
public class ClassOne {
public void method1() {
method2();
}
public void method2() {
}
}
规则2:
public class ClassOne {
public void method1(ClassTwo classTwo) {
classTwo.method2();
}
}
class ClassTwo {
public void method2() {
}
}
规则3:
public class ClassOne {
public void method1() {
ClassTwo classTwo = new ClassTwo();
classTwo.method2();
}
}
class ClassTwo {
public void method2() {
}
}
规则4(感谢@juharr):
public class ClassOne {
private ClassTwo classTwo;
public void method1() {
classTwo = new ClassTwo();
classTwo.method2();
}
}
class ClassTwo {
public void method2() {
}
}
规则5:
?
任何人都可以帮我处理规则5吗?
Demeter的法律是否意味着链接不好?
User.getName().getLastName();
这导致高耦合。
Isn&#t; tt;告诉,不要问"一个类似的原则?
这一切都是这样吗?我错了什么?你怎么能遵守得墨忒耳的法律?
答案 0 :(得分:4)
"告诉不要问"有点不同。
Demeter:在最后的事情上,不要从中得到一些东西来做点什么。 TDA:不要检索"信息"从另一个对象然后做出决定。简单的例子:if (someList.size() == 0) { bla
VS
if (someList.isEmpty()) { bla
在这两种情况下,您都在某个其他对象上调用方法;但是有一个关键的区别:第一个电话会曝光"内部"你的另一个对象的状态;然后你做出一些决定。然而,在" TDA"改进了第二版;你离开那个"状态评估"在另一个对象中;从而以某种方式减少耦合。
但仅仅是为了记录:第二个例子仍然根据该列表的状态做出决定。从这个角度来看,它只是一个略微比选项1更好的版本。理想情况下,你不需要这样的检查。
答案 1 :(得分:2)
第五种很难在C#或Java中表示,因为它们在技术上不支持全局变量。但是,在原则上类似的设计模式中,您可以使用例如一个只包含全局可访问的静态配置值的配置类,例如(C#):
class VAR1 : public Variable { };
class VAR2 : public Variable { };
System<VAR1, VAR2> s{ /* init values: ("VAR1", 10), ("VAR2", 20) */};
在这种情况下(假设设计模式在所有其他方面都是可接受的),Demeter法则允许这样做,因为它是全球可访问的并且打算这样。
答案 2 :(得分:2)
规则5的一个例子是:
public class ClassOne {
public void method1() {
classTwo.STATIC_INSTANCE.method2();
}
}
class ClassTwo {
public static final ClassTwo STATIC_INSTANCE = ...;
public void method2() {
}
}
Enums基本上都是这样工作的,访问枚举是可以的。
你的例子:
user.getName().getLastName();
显然与法律相矛盾,因为你得到的对象&#34; getName()&#34;不会属于列出的任何类别。注意:即使您没有使用链式调用,这也是错误的:
Name name = user.getName();
name.getLastName(); // <- this is still wrong
因为对象&#34;名称&#34;仍然不属于任何列出的类别。
但是这样的事情还可以:
reportBuilder.withMargin(5).withFooter(10)
.withBorder(Color.black).build();
为什么允许这样做?因为每次都要返回相同的对象(reportBuilder),或者每次将构建器实现为不可变时都可能是新对象。无论哪种方式,它都属于法律2或3,所以无论如何都可以。
你的第三个问题是&#34;如何服从&#34;。嗯,这是一个复杂的问题,但是刚开始,想想法律实际上禁止哪种方法!
只是将法律置于否定之中:我们不应该在已经存在的对象上调用方法(因为新对象是免除的),而不是我的对象,或者我的对象的字段,或者我的参数。这样就会留下其他对象字段中的对象!
所以基本上这意味着你不应该能够&#34;得到&#34;访问不是您的对象,而不是您的字段,而不是直接参数。我总结为&#34;没有吸气者&#34;!