Oop 德米特定律与类构造函数

Oop 德米特定律与类构造函数,oop,law-of-demeter,Oop,Law Of Demeter,不阻止将对象传递给类构造函数。但是,它确实禁止稍后返回同一对象并调用该对象上的方法以获取标量值。相反,应该创建一个代理方法来返回标量值。我的问题是,为什么将一个对象传递到类构造函数中是可以接受的,而将同一个对象返回并从中提取一个值是不可以接受的?这个想法是你只与你的直接朋友交谈。所以,你不能这样做 var a = new A(); var x = a.B.doSomething(); var a = new A(); var x = a.doSomething(); // where a.do

不阻止将对象传递给类构造函数。但是,它确实禁止稍后返回同一对象并调用该对象上的方法以获取标量值。相反,应该创建一个代理方法来返回标量值。我的问题是,为什么将一个对象传递到类构造函数中是可以接受的,而将同一个对象返回并从中提取一个值是不可以接受的?

这个想法是你只与你的直接朋友交谈。所以,你不能这样做

var a = new A();
var x = a.B.doSomething();
var a = new A();
var x = a.doSomething(); // where a.doSomething might call b.doSomething();
相反,你这样做

var a = new A();
var x = a.B.doSomething();
var a = new A();
var x = a.doSomething(); // where a.doSomething might call b.doSomething();

它有它的优点,因为对于调用方来说事情变得更简单(Car.Start()和Car.Engine.Start()),但是您可以得到很多小包装方法。您还可以使用来缓解这种类型的“违规行为”。

JP的回答非常好,因此这只是一个补充,而不是一个分歧或其他替代

我理解这种启发式的方式是,对a的调用不应该因为B类的更改而中断。因此,如果使用a.b.foo()链接调用,则a的接口将依赖于b的接口,这违反了规则。相反,您应该调用a.BFoo(),它为您调用b.foo()

这是一个很好的经验法则,但它可能会导致一些笨拙的代码,这些代码并没有真正解决依赖关系,而是将其隐藏起来。现在A必须永远提供BFoo,即使B不再提供Foo。这并没有多大的改进,至少在某些情况下,如果对B的更改破坏了想要Foo的调用方,而不是B本身,可能会更好


我还要补充一点,严格地说,对于一组无处不在的类,比如字符串,这个规则经常被打破。也许可以接受的做法是,决定哪些类在应用程序的特定层中同样普遍存在,并自由地忽略Demeter的“规则”。

因为Demeter定律说,您不应该设计对象的外部接口,使其看起来像是由具有已知接口的某些其他对象组成,客户只需抓住并访问即可

您将一个对象传递到构造函数中,告诉您的新对象如何行为,但该对象是否保留该参数对象、是否保留该参数对象的副本,或者只是查看它一次并忘记它曾经存在,与您无关。通过使用getMyParameterBack方法,您已经承诺了所有未来的实现都能够按需生成整个对象,并且所有客户机都将使用两个接口而不是一个接口进行耦合

例如,如果您将URL参数传递给HTTPRequest对象的构造函数,那么这并不意味着HTTPRequest应该有一个getURL方法,该方法返回一个URL对象,然后调用者将在该对象上调用getProtocol、getQueryString等。如果有HTTPRequest对象的人可能想知道请求的协议,他们应该(法律规定)通过在他们拥有的对象上调用getProtocol来发现,而不是在他们碰巧知道HTTPRequest正在内部存储的其他对象上

这个想法是为了减少耦合——在没有德米特定律的情况下,用户必须知道HTTPRequest和URL的接口,才能获得协议。根据法律,他们只需要HTTPRequest的接口。显然,HTTPRequest.getProtocol()可以返回“http”,而不需要讨论中涉及一些URL对象

有时请求对象的用户恰好是创建它的人,因此也在使用URL接口来传递参数,这一事实既不存在,也不存在。并非所有HTTPRequest对象的用户都会自己创建它们。因此,根据法律有权访问URL的客户(因为他们自己创建了URL)可以这样做,而不是从请求中夺回URL。无法创建URL的客户端

就我个人而言,我认为通常以简单形式表述的得墨忒尔定律已经被破解了。他们是不是认真地说,如果我的对象有一个字符串名称字段,我想知道该名称是否包含任何非ASCII字符,那么我必须在对象上定义一个NameContains NasciCharacters方法,而不是查看字符串本身,或者在类中添加一个visitName函数作为回调函数,以确保字符串是我编写的函数的参数,从而绕过限制?这根本不会改变耦合,它只是用visitor方法替换getter方法。如果我想操作返回值,每个返回整数的类是否都应该有一整套算术运算?getPriceMultipliedBy(整数n)?当然不是


它的用处在于,当你破坏它时,你可以问自己为什么要破坏它,以及是否可以通过不破坏它来设计更好的界面。通常你可以,但实际上这取决于你在谈论什么样的对象。某些接口可以安全地与大量代码(如整数、字符串,甚至URL)耦合,它们代表了广泛使用的概念。

您能提供一个指向“直径定律”的链接吗?我以前从未听说过德米特定律,所以。。。需要委托给B的方便函数,这是很有道理的,但是“B getB()const”被禁止了吗?如果是,为什么?这就是法律的全部理念。。。可以重述一下“你只和你的直系朋友说话”,这有什么好处?这个想法由来已久。这些天来,我们正在编写非常松散耦合的应用程序。这里必须+1你,因为你说的和我一样,只是更短更快:-)我回敬了你,因为你包括了一个很好的例子。你看,Uri包装器正是那种无处不在的类,我可以从这个规则中豁免,就像字符串一样。被视为达到目的的手段,这是一条很好的经验法则,但它本身并不是目的。我们的目标是隐藏内部的实现细节,而不是故弄玄虚