Language agnostic 德米特违反法证明是有用的。我错过什么了吗?

Language agnostic 德米特违反法证明是有用的。我错过什么了吗?,language-agnostic,law-of-demeter,Language Agnostic,Law Of Demeter,我的应用程序中有一些类似的代码。它写出了一些XML:- public void doStuff( Business b, XMLElement x) { Foo f = b.getFoo(); // Code doing stuff with f // b is not mentioned again. } 据我所知,德门特定律会说这是不好的。“代码完成”说这是增加耦合。这种方法首先应该取“f” public void doStuff( Foo f, XMLElement x

我的应用程序中有一些类似的代码。它写出了一些XML:-

public void doStuff( Business b, XMLElement x)
{
   Foo f = b.getFoo();
   // Code doing stuff with f
   // b is not mentioned again.
}
据我所知,德门特定律会说这是不好的。“代码完成”说这是增加耦合。这种方法首先应该取“f”

public void doStuff( Foo f, XMLElement x)
{
    // Code doing stuff with f
}
然而,现在我来更改这段代码,我确实需要访问
b
上的另一个方法

public void doStuff( Business b, XMLElement x)
{
   Foo f = b.getFoo();
   // Code doing stuff with f
   // A different method is called on b.
}
由于更改完全在方法内部,因此此接口使操作变得更简单。我不必担心应用程序中调用它的地方太多

这向我表明原来的设计是正确的。你同意吗?我错过了什么


注:我认为这种行为不属于b本身,因为域对象不知道在这个系统中作为XML的外部表示。

如果我们进一步遵循这个逻辑,我们会想出一个想法,即全局所有对象存储库对象(或服务定位器)应使用包含指向系统中所有内容的链接的。这样我们就根本不需要更改方法签名,因为我们只需要这个存储库


问题是该方法的目的已经改变,但签名没有改变。如果Foo是方法所需要的一切,那么它应该只接受Foo。通过这种方式,我们可以看出它只在Foo上运行。这将更清楚地传达该方法的目的。如果它突然也需要业务,我们需要更改方法签名,因为它应该指示其他方法用途和要求

如果我们进一步遵循此逻辑,我们会想到应该使用全局所有对象存储库对象(或服务定位器),其中包含指向系统中所有内容的链接。这样我们就根本不需要更改方法签名,因为我们只需要这个存储库


问题是该方法的目的已经改变,但签名没有改变。如果Foo是方法所需要的一切,那么它应该只接受Foo。通过这种方式,我们可以看出它只在Foo上运行。这将更清楚地传达该方法的目的。如果它突然也需要业务,我们需要更改方法签名,因为它应该指示其他方法的用途和要求

可能现在有理由传入业务,或者该方法需要第三个参数:在业务对象上调用的其他方法的返回类型。它取决于doStuff方法主体的其余部分。

可能现在有理由传入业务,或者该方法需要第三个参数:在业务对象上调用的另一个方法的返回类型。这取决于doStuff方法主体的其余部分。

我认为很难给你一个明确的答案,因为

1) 问题陈述非常抽象,
2) 没有“绝对”好的设计——这也取决于你的类周围有什么,好的设计最初可能会随着系统的发展演变成你想要重构的东西,你对领域的理解也会变得更加精细


我不认为第一个例子“大规模”违反了德米特原则,但同样,一切都在细节中,这取决于你评论的部分有多少内容——如果需要,你可以添加更多的间接性。例如,您可以在WriteBusinessObjectToXmlService类上使用方法“DoStuff”,如果涉及f的工作量在增加,您可以将其提取到其方法“dostufwithf(f,x)”中,甚至使用DoStuff(f,x)创建一个单独的类WriteFToXmlService我想很难给你一个明确的答案,因为

1) 问题陈述非常抽象,
2) 没有“绝对”好的设计——这也取决于你的类周围有什么,好的设计最初可能会随着系统的发展演变成你想要重构的东西,你对领域的理解也会变得更加精细


我不认为第一个例子“大规模”违反了德米特原则,但同样,一切都在细节中,这取决于你评论的部分有多少内容——如果需要,你可以添加更多的间接性。例如,您可以在WriteBusinessObjectToXmlService类上使用方法“DoStuff”,如果涉及f的工作量在增加,您可以将其提取到其方法“dostufwithf(f,x)”中,甚至使用DoStuff(f,x)创建一个单独的类WriteFToXmlService.

首先,这不一定是违反德米特定律的,除非您实际上是在doStuff中对Foo对象f调用方法。如果你不是,那么你可能很好;您只使用业务对象b的接口。因此,我假设您至少在“f”上调用了一个方法

您可能“缺少”的一件事是可测试性,特别是单元测试。如果您有:

public void doStuff( Business b, XMLElement x)
{
    Foo f = b.getFoo();
    // stuff using f.someMethod
    // business stuff with b
    // presumably something with x
}
。。。然后,如果您想测试doStuff是否对不同的Foo做了正确的事情,您必须首先使用您想要的每个Foo'f'创建(或模拟)一个新的业务对象,然后将该对象插入doStuff(即使其他特定于业务的内容是相同的)。您只需从方法中删除一次即可进行测试,虽然源代码可能保持简单,但测试代码会变得更加混乱。所以,如果您真的需要doStuff中的f和b,那么可以说它们都应该是参数


对于更多的阅读,他是我遇到的最坚定的竞选者之一;经常提供这种方法。

首先,这不一定是违反德米特定律的,除非您实际上是在doStuff中对Foo对象f调用方法。如果你不是,那么你可能很好;您只使用业务对象b的接口。因此,我假设您至少在“f”上调用了一个方法

您可能“缺少”的一件事是可测试性,具体的