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

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

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

再简洁些:

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

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

更简洁些:

Only talk to your immediate friends.

只和自己直接的 "朋友" 交谈。

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

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),这会提升类设计的复杂度。

面向对象设计的原则

 SRP

单一职责原则

Single Responsibility Principle

 OCP

开放封闭原则

Open Closed Principle

 LSP

里氏替换原则

Liskov Substitution Principle

ISP

接口分离原则

Interface Segregation Principle

 DIP

依赖倒置原则

Dependency Inversion Principle

 LKP

最少知识原则

Least Knowledge Principle

参考资料

本文《最少知识原则(Least Knowledge Principle)》由 Dennis Gao 原创并发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫行为均为耍流氓。

最少知识原则(Least Knowledge Principle)的更多相关文章

  1. 北风设计模式课程---最少知识原则(Least Knowledge Principle)

    北风设计模式课程---最少知识原则(Least Knowledge Principle) 一.总结 一句话总结: 最少知识原则(Least Knowledge Principle),或者称迪米特法则( ...

  2. 设计模式值六大原则——迪米特法则(LoD)也称为最少知识原则(LKP)。

    定义: 迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP). 一个对象应该对其他对象有最少的了解.通俗地讲,一个类应该对 ...

  3. 设计模式之迪米特原则(LOD)(最少知识原则)

    来源:迪米特法则(LoD)最初是用来作为面向对象的系统设计风格的一种法则,是很多著名系统,如火星登陆软件系统.木星的欧罗巴卫星轨道飞船的软件系统的指导设计原则. 迪米特法则(LoD)又可分为两种:狭义 ...

  4. [Python设计模式] 第11章 迪米特法则——最少知识原则

    github地址:https://github.com/cheesezh/python_design_patterns 迪米特法则 迪米特法则(LoD),也叫最少知识原则,如果两个类不必彼此直接通信, ...

  5. Java设计模式之外观模式和最少知识原则

    外观模式: 外观模式:提供一个统一的接口,来访问子系统中一群功能相关接口(类似一键启动,一键关闭等等) 外观模式定义了一个高层接口,让子系统更容易使用 降低对外接口耦合度 外观模式和命令模式各自侧重点 ...

  6. 迪米特法则(LoD),即最少知识原则

    解释: 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用. 重点: 在类的结构上,每个类都应当尽量降低成员 ...

  7. 设计模式-设计原则(Design Principle)

    本文由@呆代待殆原创,转载请注明出处. 写在前面:所谓设计原则并不是一定要遵守的法则,只是一种建议,因为保持这些原则本身会有一定代价,若是这些代价超过了带来的好处就得不偿失了,所以一切还是以简单为准. ...

  8. 命令查询分离原则Command-query separation principle

    在UML和模式应用一书中,发送给Die的roll消息之后跟随着第二个消息getFaceValue用于提取其新的faceValue,特别是:roll()方法是void的,没有返回值,例如: public ...

  9. 面象对象设计原则之一:单一职责原则(Single Responsibility Principle, SRP)

    单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小.单一职责原则定义如下:单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域 ...

随机推荐

  1. discuz二次开发,分析和实现 之 向dz数据库插入自己的帖子吧

    发个博客太麻烦了,难怪写博客的越来越少,吐一下,cnblogs的编辑器模板太丑! 最近开发社区 需要采集一些数据,使得模板输出有图文效果.就写了个简单的采集脚本,爬取目标站的内容,(用php 下载图片 ...

  2. win7+vs2010+opencv2.4.6配置

    记录一下配置,省的以后还到处去找: (一) 添加环境变量://第一次使用opencv的话需要加环境变量:” %opencv%\build\x86\vc10\bin”和”%opencv%\build\c ...

  3. asp.net下AjaxMethod的使用方法

    使用AjaxMethod可以在客户端异步调用服务端方法,简单地说就是在JS里调用后台.cs文件里的方法, 做一些JS无法做到的操作,如查询数据库 使用AjaxMethod要满足一下几点: 1.如果还没 ...

  4. Linux C++ 开发常用工具,常用指令工作手册

    vim常用: :set nu显示行数 :set mouse=a 鼠标滑动屏幕,:set ic :set noic 忽略不忽略大小写 /word_to_search\c \c表示忽略大小写 c小写忽略, ...

  5. C# 并行编程 之 轻量级手动重置事件的使用

    目录(?)[-] 简单介绍 使用超时和取消 跨进程或AppDomain的同步   简单介绍 如果预计操作的等待的时间非常短,可以考虑使用轻量级的手动重置事件,ManualResetEventSlim. ...

  6. js动态生成二维码图片

    1.html代码 <div id="qrcode" style="width:200px; height:200px;position: fixed;bottom: ...

  7. [翻译][erlang]cowboy handler模块的使用

    关于Cowboy Cowboy是基于Erlang实现的一个轻量级.快速.模块化的http web服务器. Handlers,用于处理HTTP请求的程序处理模块. Plain HTTP Handlers ...

  8. jvm 原理和优化

    在csdn 上看到的,觉得很好,收藏了: 原博文地址: 濤子 http://blog.csdn.net/ning109314/article/details/10411495/ JVM工作原理和特点主 ...

  9. Surfer 软件做等值线图

    使用surfer软件做等值线图 Surfer软件美国Golden Software公司编制的一款以画三维图(等高线,image map,3d surface)的软件. Surfer具有的强大插值功能和 ...

  10. iOS多线程 NSOperation的用法

    上一篇写了 GCD 的使用,接下来就了解一下 NSOperation ,NSOperation是苹果对 GCD 的 OC 版的一个封装,但是相对于GCD来说可控性更强,并且可以加入操作依赖. NSOp ...