耦合、内聚和迪米特定律

发布于 2024-07-05 20:52:37 字数 563 浏览 10 评论 0原文

德米特法则表明你应该只与你直接了解的物体交谈。 也就是说,不要执行方法链接来与其他对象通信。 当您这样做时,您正在与中间对象建立不正确的链接,不恰当地耦合您的代码到其他代码。

那很糟。

解决方案是对于您所了解的类,本质上公开简单的包装器,将责任委托给与其有关系的对象。

那挺好的。

但是,这似乎导致班级的凝聚力较低。 它不再只是简单地负责它所做的事情,而且它还具有委托,在某种意义上,通过复制其相关对象的接口部分来降低代码的凝聚力。

那很糟。

这真的会降低凝聚力吗? 这是两害相权取其轻吗?

这是发展的灰色地带之一,您可以在其中争论界限在哪里,或者是否有强有力的、有原则的方法来决定在哪里划定界限以及可以使用什么标准来做出该决定?

The Law of Demeter indicates that you should only speak to objects that you know about directly. That is, do not perform method chaining to talk to other objects. When you do so, you are establishing improper linkages with the intermediary objects, inappropriately coupling your code to other code.

That's bad.

The solution would be for the class you do know about to essentially expose simple wrappers that delegate the responsibility to the object it has the relationship with.

That's good.

But, that seems to result in the class having low cohesion. No longer is it simply responsible for precisely what it does, but it also has the delegates that in a sense, making the code less cohesive by duplicating portions of the interface of its related object.

That's bad.

Does it really result in lowering cohesion? Is it the lesser of two evils?

Is this one of those gray areas of development, where you can debate where the line is, or are there strong, principled ways of making a decision of where to draw the line and what criteria you can use to make that decision?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦屿孤独相伴 2024-07-12 20:52:37

如果您违反了德米特法则,解决

int price = customer.getOrder().getPrice();

方案不是创建 getOrderPrice() 并将代码转换为

int price = customer.getOrderPrice();

,而是要注意这是一个 代码味道并进行相关更改,希望既能增加内聚性,又能降低耦合。 不幸的是,这里没有始终适用的简单重构,但您可能应该应用 告诉不要询问

If you are violating the Law of Demeter by having

int price = customer.getOrder().getPrice();

the solution is not to create a getOrderPrice() and transform the code into

int price = customer.getOrderPrice();

but instead to note that this is a code smell and make the relevant changes that hopefully both increase cohesion and lower coupling. Unfortunately there is no simple refactoring here that always applies, but you should probably apply tell don't ask

星星的軌跡 2024-07-12 20:52:37

我想你可能误解了凝聚力的含义。 一个由其他几个类实现的类不一定内聚性低,只要它代表了一个清晰的概念,并且有一个明确的目的。 例如,您可能有一个 Person 类,它是根据类 Date(出生日期)、Address 和 < code>Education(此人就读的学校列表)。 您可以在 Person 中提供包装器,用于获取该人的出生年份、上一所学校或他居住的州,以避免暴露 Person 的事实根据其他类来实现。 这会减少耦合,但也会使 Person 的内聚性丝毫不减。

I think you may have misunderstood what cohesion means. A class that is implemented in terms of several other classes does not necessarily have low cohesion, as long as it represents a clear concept, and has a clear purpose. For example, you may have a class Person, which is implemented in terms of classes Date (for date of birth), Address, and Education (a list of schools the person went to). You may provide wrappers in Person for getting the year of birth, the last school the person went to, or the state where he lives, to avoid exposing the fact that Person is implemented in terms of those other classes. This would reduce coupling, but it would make Person no less cohesive.

夏了南城 2024-07-12 20:52:37

这是一个灰色地带。
这些原则旨在帮助您工作,如果您发现自己正在为他们工作(即他们妨碍您和/或您发现它使您的代码变得过于复杂),那么您就太难遵守了,您需要退后。

让它为你工作,不要为它工作。

It’s a grey area.
These principals are meant to help you in your work, if you find you’re working for them (i.e. they’re getting in your way and/or you find it over complicates your code) then you’re conforming too hard and you need to back off.

Make it work for you, don’t work for it.

笑,眼淚并存 2024-07-12 20:52:37

我不知道这是否真的会降低凝聚力。

聚合/组合都是关于一个类利用其他类来满足它通过其公共方法公开的契约。
该类不需要复制其相关对象的接口。 它实际上向方法调用者隐藏了有关这些聚合类的任何知识。

为了在多层次的类依赖的情况下遵守德米特定律,你只需要在每个层次上应用聚合/组合和良好的封装。

换句话说,每个类对其他类都有一个或多个依赖项,但是这些依赖项仅依赖于引用的类,而不依赖于从属性/方法返回的任何对象。

I don't know if this actually lowers cohesion.

Aggregation/composition are all about a class utilising other classes to meet the contract it exposes through its public methods.
The class does not need to duplicate the interface of it's related objects. It's actually hiding any knwowledge about these aggregated classes from the method caller.

To obey the law of Demeter in the case of multiple levels of class dependency, you just need to apply aggregation/composition and good encapsulation at each level.

In other words each class has one or more dependencies on other classes, however these are only ever dependencies on the referenced class and not on any objects returned from properies/methods.

心的憧憬 2024-07-12 20:52:37

在耦合和内聚之间似乎存在权衡的情况下,我可能会问自己“如果其他人已经编写了这个逻辑,并且我正在寻找其中的错误,我会首先在哪里寻找?”,并且就这样写代码。

In the situations where there seems to be a tradeoff between coupling and cohesion, I'd probably ask myself "if somebody else had already written this logic, and I were looking for a bug in it, where would I look first?", and write the code that way.

゛时过境迁 2024-07-12 20:52:37

Grady Booch在《面向对象分析与设计》中:

“内聚的思想也来自结构化设计。简单地说,内聚
测量单个模块的元素之间的连接程度(以及
对于面向对象的设计,单个类或对象)。 最不理想的形式
内聚是巧合的内聚,其中完全不相关的抽象是
扔到同一个类或模块中。 例如,考虑一个包含以下内容的类:
狗和航天器的抽象,它们的行为完全无关。 这
最理想的内聚形式是功能内聚,其中的要素
类或模块一起工作以提供一些有界的行为。
因此,如果 Dog 类的语义包含行为,那么它在功能上是内聚的
狗,整只狗,除了狗什么都没有。”

在上面用“客户”代替“狗”,可能会更清楚一些。因此,目标实际上只是为了实现功能内聚,并尽可能远离巧合内聚根据您的抽象,这可能很简单,也可能需要一些重构。

注意,内聚力适用于“模块”而不是单个类,即一组一起工作的类。订单类仍然具有良好的凝聚力,因为它们具有很强的关系,客户创建订单,订单属于客户。Martin

Fowler 表示,他更愿意将其称为“Demeter 的建议”(请参阅​​文章 Mock 不是存根):

"Mockist 测试人员确实更多地谈论如何避免“火车残骸” - getThis() 风格的方法链.getThat().getTheOther()。 避免方法链也称为遵循德米特定律。 虽然方法链是一种气味,但相反的中间人对象因转发方法而臃肿的问题也是一种气味。 (我一直觉得如果德墨忒尔定律被称为德墨忒尔建议,我会更舒服。)”

这很好地总结了我的观点:它是完全可以接受的并且通常需要具有比严格遵守“法律”可能要求的更低水平的内聚力,避免巧合的内聚力并以功能内聚力为目标,但不要沉迷于需要更自然地适应您的设计的地方进行调整。抽象。

Grady Booch in "Object Oriented Analysis and Design":

"The idea of cohesion also comes from structured design. Simply stated, cohesion
measures the degree of connectivity among the elements of a single module (and
for object-oriented design, a single class or object). The least desirable form of
cohesion is coincidental cohesion, in which entirely unrelated abstractions are
thrown into the same class or module. For example, consider a class comprising
the abstractions of dogs and spacecraft, whose behaviors are quite unrelated. The
most desirable form of cohesion is functional cohesion, in which the elements of
a class or module all work together to provide some well-bounded behavior.
Thus, the class Dog is functionally cohesive if its semantics embrace the behavior
of a dog, the whole dog, and nothing but the dog."

Subsitute Dog with Customer in the above and it might be a bit clearer. So the goal is really just to aim for functional cohesion and to move away from coincidental cohesion as much as possible. Depending on your abstractions, this may be simple or could require some refactoring.

Note cohesion applies just as much to a "module" than to a single class, ie a group of classes working together. So in this case the Customer and Order classes still have decent cohesion because they have this strong relationshhip, customers create orders, orders belong to customers.

Martin Fowler says he'd be more comfortable calling it the "Suggestion of Demeter" (see the article Mocks aren't stubs):

"Mockist testers do talk more about avoiding 'train wrecks' - method chains of style of getThis().getThat().getTheOther(). Avoiding method chains is also known as following the Law of Demeter. While method chains are a smell, the opposite problem of middle men objects bloated with forwarding methods is also a smell. (I've always felt I'd be more comfortable with the Law of Demeter if it were called the Suggestion of Demeter .)"

That sums up nicely where I'm coming from: it is perfectly acceptable and often necessary to have a lower level of cohesion than the strict adherence to the "law" might require. Avoid coincidental cohesion and aim for functional cohesion, but don't get hung up on tweaking where needed to fit in more naturally with your design abstraction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文