代码之家  ›  专栏  ›  技术社区  ›  WW.

德米特违犯法律被证明是有用的。我错过什么了吗?[关闭]

  •  1
  • WW.  · 技术社区  · 15 年前

    我的应用程序中有一些类似的代码。它写出了一些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外部表示。

    4 回复  |  直到 15 年前
        1
  •  4
  •   Zac Thompson    15 年前

    首先,这不一定是违反德米特定律,除非您实际上在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,那么可以说它们都应该是参数。

    想了解更多信息, this person 是最有力的 Law of Demeter 我遇到的竞选者;经常提供 rationales 为了它。

        2
  •  2
  •   Mathias    15 年前

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

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

    我不认为第一个例子是对德米特原理的“大规模”违反,但同样的,一切都在细节中,这取决于你的评论部分到底发生了多少——如果你需要的话,你可以添加更多的间接性。例如,您可以将方法“dostuff”放在一个writebusinessobjectToxmlservice类上,如果您所做的涉及f的工作量正在增加,则可以将其提取到方法“dostuffithf(f,x)”中,甚至可以使用dostuff(f,x)创建一个单独的类writeftoxmlservice。

        3
  •  1
  •   artemb    15 年前

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

    问题是该方法的目的已更改,但签名尚未更改。如果foo是方法所需的一切,那么它应该只接受foo。这样我们就可以知道它只在foo上运行。这将更清楚地传达方法的目的。如果它突然也需要业务,我们需要更改方法签名,因为它应该指示其他方法目的和要求。

        4
  •  0
  •   Rian Schmits    15 年前

    也许现在有理由传入业务,或者该方法需要第三个参数:对业务对象调用的其他方法的返回类型。这取决于身体其他部位的剂量测定方法。