最少知识原则(Least Knowledge Principle)
最少知识原则(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 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 方法仅能访问如下这些类型的对象:
- O 对象自身;
- m 方法的参数对象;
- 任何在 m 方法内创建的对象;
- 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);
}
上面这个设计有几点问题:
- 复杂而且看起来不必要。Emailer 与多个它可能不是真的需要的 API 进行交互,例如 EmailSystem。
- 依赖于 Server 和 EmailSystem 的内部结构,如果两者之一进行了修改,则 Emailer 有可能被破坏。
- 不能重用。任何其他的 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 | ||
| OCP | ||
| LSP | ||
|
ISP |
||
| DIP | ||
| LKP |
参考资料
- Principle of Least Knowledge
- Demeter: Aspect-Oriented Software Development
- Law of Demeter
- Controlling the Complexity of Software Designs
- Introducing Demeter and its Laws
- The Paperboy, The Wallet, and The Law Of Demeter
- Principle of Least Knowledge
- Loose Coupling with Demeter
- An Empirical Validation of the Benefits of Adhering to the Law of Demeter
本文《最少知识原则(Least Knowledge Principle)》由 Dennis Gao 原创并发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫行为均为耍流氓。
最少知识原则(Least Knowledge Principle)的更多相关文章
- 北风设计模式课程---最少知识原则(Least Knowledge Principle)
北风设计模式课程---最少知识原则(Least Knowledge Principle) 一.总结 一句话总结: 最少知识原则(Least Knowledge Principle),或者称迪米特法则( ...
- 设计模式值六大原则——迪米特法则(LoD)也称为最少知识原则(LKP)。
定义: 迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP). 一个对象应该对其他对象有最少的了解.通俗地讲,一个类应该对 ...
- 设计模式之迪米特原则(LOD)(最少知识原则)
来源:迪米特法则(LoD)最初是用来作为面向对象的系统设计风格的一种法则,是很多著名系统,如火星登陆软件系统.木星的欧罗巴卫星轨道飞船的软件系统的指导设计原则. 迪米特法则(LoD)又可分为两种:狭义 ...
- [Python设计模式] 第11章 迪米特法则——最少知识原则
github地址:https://github.com/cheesezh/python_design_patterns 迪米特法则 迪米特法则(LoD),也叫最少知识原则,如果两个类不必彼此直接通信, ...
- Java设计模式之外观模式和最少知识原则
外观模式: 外观模式:提供一个统一的接口,来访问子系统中一群功能相关接口(类似一键启动,一键关闭等等) 外观模式定义了一个高层接口,让子系统更容易使用 降低对外接口耦合度 外观模式和命令模式各自侧重点 ...
- 迪米特法则(LoD),即最少知识原则
解释: 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用. 重点: 在类的结构上,每个类都应当尽量降低成员 ...
- 设计模式-设计原则(Design Principle)
本文由@呆代待殆原创,转载请注明出处. 写在前面:所谓设计原则并不是一定要遵守的法则,只是一种建议,因为保持这些原则本身会有一定代价,若是这些代价超过了带来的好处就得不偿失了,所以一切还是以简单为准. ...
- 命令查询分离原则Command-query separation principle
在UML和模式应用一书中,发送给Die的roll消息之后跟随着第二个消息getFaceValue用于提取其新的faceValue,特别是:roll()方法是void的,没有返回值,例如: public ...
- 面象对象设计原则之一:单一职责原则(Single Responsibility Principle, SRP)
单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小.单一职责原则定义如下:单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域 ...
随机推荐
- discuz二次开发,分析和实现 之 向dz数据库插入自己的帖子吧
发个博客太麻烦了,难怪写博客的越来越少,吐一下,cnblogs的编辑器模板太丑! 最近开发社区 需要采集一些数据,使得模板输出有图文效果.就写了个简单的采集脚本,爬取目标站的内容,(用php 下载图片 ...
- win7+vs2010+opencv2.4.6配置
记录一下配置,省的以后还到处去找: (一) 添加环境变量://第一次使用opencv的话需要加环境变量:” %opencv%\build\x86\vc10\bin”和”%opencv%\build\c ...
- asp.net下AjaxMethod的使用方法
使用AjaxMethod可以在客户端异步调用服务端方法,简单地说就是在JS里调用后台.cs文件里的方法, 做一些JS无法做到的操作,如查询数据库 使用AjaxMethod要满足一下几点: 1.如果还没 ...
- Linux C++ 开发常用工具,常用指令工作手册
vim常用: :set nu显示行数 :set mouse=a 鼠标滑动屏幕,:set ic :set noic 忽略不忽略大小写 /word_to_search\c \c表示忽略大小写 c小写忽略, ...
- C# 并行编程 之 轻量级手动重置事件的使用
目录(?)[-] 简单介绍 使用超时和取消 跨进程或AppDomain的同步 简单介绍 如果预计操作的等待的时间非常短,可以考虑使用轻量级的手动重置事件,ManualResetEventSlim. ...
- js动态生成二维码图片
1.html代码 <div id="qrcode" style="width:200px; height:200px;position: fixed;bottom: ...
- [翻译][erlang]cowboy handler模块的使用
关于Cowboy Cowboy是基于Erlang实现的一个轻量级.快速.模块化的http web服务器. Handlers,用于处理HTTP请求的程序处理模块. Plain HTTP Handlers ...
- jvm 原理和优化
在csdn 上看到的,觉得很好,收藏了: 原博文地址: 濤子 http://blog.csdn.net/ning109314/article/details/10411495/ JVM工作原理和特点主 ...
- Surfer 软件做等值线图
使用surfer软件做等值线图 Surfer软件美国Golden Software公司编制的一款以画三维图(等高线,image map,3d surface)的软件. Surfer具有的强大插值功能和 ...
- iOS多线程 NSOperation的用法
上一篇写了 GCD 的使用,接下来就了解一下 NSOperation ,NSOperation是苹果对 GCD 的 OC 版的一个封装,但是相对于GCD来说可控性更强,并且可以加入操作依赖. NSOp ...