最少知识原则(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 University 的 Ian 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 方法仅能访问以下这些类型的对象:
具体点儿就是,对象应尽量地避免调用由另外一个方法返回的对象的方法。
现代面向对象程序设计语言一般使用 "." 做为访问标识,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); }
上面这个设计有几点问题:
除了上面这几个问题以外,还有一个问题是这段代码是可测试的吗?你可能会说确定可测啊,由于这个类使用了依赖注入(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),这会提高类设计的复杂度。
参考资料