应用具有立面图案的DEMETER法则

Maa*_*mon 13 design-patterns law-of-demeter

在敏捷开发人员的基本技能方面,在需求与能力界面,第12章,我试图理解提出的主要解决方案,以应用作者在本章末尾提到的DEMETER法案.

简而言之.

我们从以下研究案例开始:

public class City {
  public string name{};
  public City twinCity{};
  public Street[] streets{};
}
public class Street {
  public string name{};
  public House[] houses{};
}
public class House {
  public int number{};
  public Color color{};
}
Run Code Online (Sandbox Code Playgroud)

城市网格模型

作者声明:

这样的模型鼓励我们揭露而不是封装.如果您的代码具有对特定城市实例的引用,例如一个映射西雅图的实例,并且您想要1374 Main Street的房子颜色,那么您可能会执行以下操作:

public Foo() {
  Color c = Seattle.streets()["Main"].
    houses()[1374].
    color();
}
Run Code Online (Sandbox Code Playgroud)

如果这是作为一般实践完成的,那么问题在于系统在任何地方都会开发依赖关系,并且对此模型的任何部分的更改都可以在这些依赖关系的链中产生影响.这就是德米特定律,即"不要与陌生人交谈"的内容.这在对象系统中被形式化为函数/方法的得墨忒耳定律.对象O的方法M只能调用以下类型的对象的方法:

  1. O公司
  2. M的参数
  3. 在M中实例化的任何对象
  4. O的直接组件对象
  5. O可访问的任何全局变量

并建议在应用DEMTER法则时,我们应该瞄准类似的东西

public Foo() {
   Color c = Seattle.ColorOfHouseInStreet("Main",1374);
}
Run Code Online (Sandbox Code Playgroud)

并迅速从以下警告:

虽然这最初似乎是一个明智的政策,但它很快就会失控,因为任何特定实体的界面都可以预期提供与其相关的字面意义.随着时间的推移,这些界面往往会膨胀,实际上,给定玻璃可能最终支持的公共方法的数量似乎几乎没有结束.

然后在快速绕道解释耦合和依赖的问题之后,他提到了通过服务接口分离客户端及其服务的重要性,并可能进一步将客户端"需求接口"与"服务能力"分开界面"通过使用适配器作为理想但不一定实用的东西;

理想的解耦

他建议为了解决这个问题,我们可以将DEMETER的法则与需求/能力分离相结合,使用外观模式解释如下:

从原来的依赖

违反了得墨忒耳的法律

在应用demeter定律和需求/能力接口分离时,我们应该首先得到:

太复杂了

但鉴于从嘲讽的角度来看这是不切实际的,我们可以通过以下方式获得更简单的外观:

LoD需求/能力分离 嘲笑

问题是我只是看不出这是如何解决不违反得墨忒耳法的问题.我认为它维护原始客户和原始服务之间的法律.但它只是在FACADE中移动了违规行为.

tca*_*vin 3

我想说,根据您的描述,他只是以 CityMapFacade 的形式围绕 Cirty/Street/House 功能引入了一个黑盒组件。此外,该组件以接口 IClientNeeds 的形式遵循面向公众的接口。这种黑盒封装可以保护更大的应用程序并使之可测试,因为城市/街道/房屋关系的复杂性没有暴露出来。看起来曾经旧的又是新的了:) 这种黑盒组件式方法(由于缺乏更好的术语)已经存在很长时间了。它专注于创建具有定义良好的接口的可重用、封装的功能组件。只要履行面向公众的合同,客户并不关心实施情况。该组件是可替换的、可升级的、可模拟的。在组件内,复杂性也降低了,因为它只负责应用程序的一个隔离子集。它通常是完全可单元测试的,以确保它正确实现其公共契约/接口。在我看来,作者隐藏了对这一切的更深入的讨论,以简化他的解释。

  • 这是一个视角问题。是的,他通过限制 CityMap 功能将德米特法则应用到应用程序/系统中。那么,CityMap组件的实现是否也遵循德米特定律呢?它可以(正如他所讨论的),但从更大系统的角度来看,这并不重要。务实地说,香肠必须在某个地方制作,有时会很混乱。我认为作者故意没有深入探讨这一点,因为这不符合他的主题。 (2认同)