设计模式-----最少知识原则

最少知识原则

最少知识原则(Least Knowledge Principle), 最少知识原则(Least Knowledge Principle),或者称迪米特法则(Law of Demeter),是一种面向对象程序设计的指导原则,它描述了一种保持代码松耦合的策略。其可简单的概括为:html

Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.编程

每一个单元对其余单元只拥有有限的知识,只了解与当前单元紧密联系的单元;app

再简洁些:less

Each unit should only talk to its friends; don't talk to strangers.函数

每一个单元只能和它的 "朋友" 交谈,不能和 "陌生人" 交谈;测试

更简洁些:设计

Only talk to your immediate friends.code

只和本身直接的 "朋友" 交谈。orm

应用到面向对象的程序设计中时,可描述为 "类应该与其协做类进行交互但无需了解它们的内部结构"。server

A class should interact directly with its collaborators and be shielded from understanding their internal structure.

迪米特法则(Law of Demeter)由 Northeastern UniversityIan Holland 在 1987 年提出,"Law of Demeter" 名称是来自当时正在进行的一项研究 "The Demeter Project"。

Demeter = Greek Goddess of Agriculture; grow software in small steps.

在 2004 年,Karl Lieberherr 在其论文 "Controlling the Complexity of Software Designs" 中将 LoD 的定义由 "Only talk to your friends" 改进为:

Only talk to your friends who share your concerns.

改进后的原则称为 LoDC(Law of Demeter for Concerns),它为软件设计带来了两个主要的益处:

It leads to better information hiding.

It leads to less information overload.

即,更好的信息隐藏和更少的信息重载。LoDC 原则在面向方面的软件开发(AOSD:Aspect-Oriented Software Development)中有着良好的应用。

最少知识原则在面向对象编程中的应用

在 "Law of Demeter" 应用于面向对象编程中时,能够简称为 "LoD-F:Law of Demeter for Functions/Methods"。

对于对象 O 中的一个方法 m ,m 方法仅能访问以下这些类型的对象:

  1. O 对象自身;
  2. m 方法的参数对象;
  3. 任何在 m 方法内建立的对象;
  4. O 对象直接依赖的对象;

具体点儿就是,对象应尽量地避免调用由另外一个方法返回的对象的方法。

现代面向对象程序设计语言一般使用 "." 做为访问标识,LoD 能够被简化为 "仅使用一个点(use only one dot)"。也就是说,代码 a.b.Method() 违反了 LoD,而 a.Method() 则符合 LoD。打个比方,人能够命令一条狗行走,可是不该该直接指挥狗的腿行走,应该由狗去指挥它的腿行走。

你是否见过相似下面这样儿的代码?

public Emailer(Server server) {…} // taking a server in the constructor
public void sendSupportEmail(String message, String toAddress) {
    EmailSystem emailSystem = server.getEmailSystem();
    String fromAddress = emailSystem.getFromAddress();
    emailSystem.getSenderSubsystem().send(fromAddress, toAddress, message);
}

上面这个设计有几点问题:

  1. 复杂并且看起来没必要要。Emailer 与多个它可能不是真的须要的 API 进行交互,例如 EmailSystem。
  2. 依赖于 Server 和 EmailSystem 的内部结构,若是二者之一进行了修改,则 Emailer 有可能被破坏。
  3. 不能重用。任何其余的 Server 实现也必须包含一个能返回 EmailSystem 的 API。

除了上面这几个问题以外,还有一个问题是这段代码是可测试的吗?你可能会说确定可测啊,由于这个类使用了依赖注入(Dependency Injection),咱们能够模拟 Server、EmailSystem 和 Sender 类。但真正的问题是,除了多出了这些模拟代码,任何对 API 的修改都将破坏全部的测试用例,使得设计和测试都变得很是脆弱。

解决上述问题的办法就是应用最少知识原则,仅经过构造函数注入直接依赖的对象。Emailer 无需了解是否 Server 类包含了一个 EmailSystem,也不知道 EmailSystem 包含了一个 Sender。

public Emailer(Sender sender, String fromAddress) {…}
public void sendSupportEmail(String message, String toAddress) {
    sender.send(fromAddress, toAddress, message);
}

这个设计较为合理些。如今 Emailer 再也不依赖 Server 和 EmailSystem,而是经过构造函数获得了全部的依赖项。同时 Emailer 也变得更容易理解,由于全部与其交互的对象都显式的呈现出来。

Emailer 与 Server 和 EmailSystem 也达到了解耦合的效果。Emailer 再也不须要了解 Server 和 EmailSystem 的内部结构,任何对 Server 和 EmailSystem 的修改都再也不会影响 Emailer。

并且,Emailer 的变得更易被复用。若是切换到另一个环境中时,仅需实现一个不一样的 Sender 便可。

对于测试而言,如今咱们仅需模拟 Sender 依赖便可。

应用最少知识原则优势和缺点

优势:遵照 Law of Demeter 将下降模块间的耦合,提高了软件的可维护性和可重用性。

缺点:应用 Law of Demeter 可能会致使不得不在类中设计出不少用于中转的包装方法(Wrapper Method),这会提高类设计的复杂度。

参考资料

相关文章
相关标签/搜索