IT知识库 购物 网址 游戏 小说 歌词 快照 开发 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 编程 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> Java -> 设计模式原则之迪米特法则 -> 正文阅读

[Java]设计模式原则之迪米特法则

设计模式原则之迪米特法则 迪米特法则的简写为 LoD,看清楚中间的那个 o 是小写。迪米特法则也叫做做最少知识原则(Least Knowledge Principle,简称 LKP)说的都是一会事,一个对象应该对其他对象有最少的了解,通俗的讲一 个类对自己需要耦合或者调用的类应该知道的最少,你类内部是怎么复杂、怎么的纠缠不清都和我没关系, 那是你的类内部的事情,我就知道你提供的这么多 public 方法,我就调用这个;迪米特法则包含以下四层 意思:
只和朋友交流。迪米特还有一个英文解释叫做“Only talk to your immedate friends”,只和直接 的朋友通信,什么叫做直接的朋友呢?每个对象都必然会和其他对象有耦合关系,两个对象之间的耦合就 成为朋友关系,这种关系有很多比如组合、聚合、依赖等等。我们来说个例子说明怎么做到只和朋友交流。 说是有这么一个故事,老师想让体育委员确认一下全班女生来齐没有,就对他说:“你去把全班女生清 一下。”体育委员没听清楚,或者是当时脑子正在回忆什么东西,就问道:“亲哪个?”老师¥#……¥%。 我们来看这个笑话怎么用程序来实现,先看类图:

Teacher.java 的源程序如下:

package com.cbf4life.common;
import java.util.ArrayList;
import java.util.List;
/**
* I'm glad to share my knowledge with you all.
* 老师类
*/
public class Teacher {
//老师对学生发布命令, 清一下女生
public void commond(GroupLeader groupLeader){
 List<Girl> listGirls = new ArrayList() ;
 //初始化女生
 for(int i=0;i<20;i++){
 listGirls.add(new Girl());
 }
 //告诉体育委员开始执行清查任务
 groupLeader.countGirls(listGirls);
 }
}

老师就有一个方法,发布命令给体育委员,去清查一下女生的数量。 下面是体育委员 GroupLeader.java 的源程序:

package com.cbf4life.common;
import java.util.List;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 体育委员,这个太难翻译了都是中国的特色词汇
*/
public class GroupLeader {
//有清查女生的工作
public void countGirls(List<Girl> listGirls){
 System. out.println(" 女生数量是: "+listGirls.size());
 }
}

下面是 Girl.java,就声明一个类,没有任何的代码:

package com.cbf4life.common;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 女生
*/
public class Girl {
}

我们来看这个业务调用类 Client:

package com.cbf4life.common;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 我们使用Client来描绘一下这个场景
*/
public class Client {
public static void main(String[] args) {
 Teacher teacher= new Teacher();
 //老师发布命令
 teacher.commond(new GroupLeader());
 }
}

运行的结果如下:

女生数量是: 20

我们回过头来看这个程序有什么问题,首先来看 Teacher 有几个朋友,就一个 GroupLeader 类,这个 就是朋友类,朋友类是怎么定义的呢? 出现在成员变量、方法的输入输出参数中的类被称为成员朋友类, 迪米特法则说是一个类只和朋友类交流, 但是 commond 方法中我们与 Girl 类有了交流,声明了一个 List动态数组,也就是与一个陌生的类 Girl 有了交流,这个不好,那我们再来修改一下,类图还是不变,先修改一下 GroupLeader 类,看源码:

package com.cbf4life.common2;
import java.util.ArrayList;
import java.util.List;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 体育委员,这个太难翻译了都是中国的特色词汇
*/
public class GroupLeader {
//有清查女生的工作
public void countGirls(){
 List<Girl> listGirls = new ArrayList<Girl>();
 //初始化女生
 for(int i=0;i<20;i++){
 listGirls.add(new Girl());
 }
 System. out.println(" 女生数量是: "+listGirls.size());
 }
}

下面是 Teacher.java 程序:

package com.cbf4life.common2;
/**
* 
* I'm glad to share my knowledge with you all.
* 老师类
*/
public class Teacher {
//老师对学生发布命令, 清一下女生
public void commond(GroupLeader groupLeader){
 //告诉体育委员开始执行清查任务
 groupLeader.countGirls();
 }
}

 程序做了一个简单的修改,就是把 Teacher 中的对 List初始化(这个是有业务意义的,产生出 全班的所有人员)移动到了 GroupLeader 的 countGrils 方法中,避开了 Teacher 类对陌生类 Girl 的访问, 减少系统间的耦合。记住了,一个类只和朋友交流,不与陌生类交流, 不要出现 getA().getB().getC().getD() 这种情况(在一种极端的情况下是允许出现这种访问:每一个点号后面的返回类型都相同),那当然还要和 JDK API 提供的类交流,否则你想脱离编译器存在呀!
朋友间也是有距离的。人和人之间是有距离的,太远就不是朋友了,太近就浑身不自在,这和类间关 系也是一样,即使朋友类也不能无话不说,无所不知。大家在项目中应该都碰到过这样的需求:调用一个 类,然后必须是先执行第一个方法,然后是第二个方法,根据返回结果再来看是否可以调用第三个方法, 或者第四个方法等等,我们用类图表示一下:
 

很简单的类图,实现软件安装过程的第一步做什么、第二步做什么、第三步做什么这样一个过程,我 们来看三个类的源代码,先看 Wizard 的源代码:

package com.cbf4life.common3;
import java.util.Random;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 按照步骤执行的业务逻辑类
*/
public class Wizard {
private Random rand = new Random(System. currentTimeMillis());
public int first(){
 System. out.println(" 执行第一个方法...");
 return rand.nextInt(100);
 }
//第二步
public int second(){
 System. out.println(" 执行第二个方法...");
 return rand.nextInt(100);
 }
//第三个方法
public int third(){
 System. out.println(" 执行第三个方法...");
 return rand.nextInt(100);
 }
}

分别定义了三个步骤方法,每个步骤中都有相关的业务逻辑完成指定的任务,我们使用一个随机函数 来代替业务执行的返回值。再来看软件安装过程 InstallSoftware 源码:

package com.cbf4life.common3;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 业务组装类,负责调用各个步骤
*/
public class InstallSoftware {
public void installWizard(Wizard wizard){
 int first = wizard.first();
 //根据first返回的结果,看是否需要执行second
 if(first>50){
 int second = wizard.second();
 if(second>50){
 int third = wizard.third();
 if(third >50){
 wizard.first();
 }
 }
}
}
}

其中 installWizard 就是一个向导式的安装步骤,我们看场景是怎么调用的:

package com.cbf4life.common3;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 业务场景
*/
public class Client {
public static void main(String[] args) {
 InstallSoftware invoker = new InstallSoftware();
 invoker.installWizard(new Wizard());
 }
}

 这个程序很简单,运行结果和随机数有关,我就不粘贴上来了。我们想想这个程序有什么问题吗? Wizard 类把太多的方法暴露给 InstallSoftware 类了,这样耦合关系就非常紧了,我想修改一个方法的返 回值,本来是 int 的,现在修改为 boolean,你看就需要修改其他的类,这样的耦合是极度不合适的, 迪米 特法则就要求类“小气”一点,尽量不要对外公布太多的 public 方法和非静态的 public 变量, 尽量内敛, 多使用 private,package-private、protected 等访问权限。我们来修改一下类图:

我们再来看一下程序的变更,先看 Wizard 程序:

package com.cbf4life.common4;
import java.util.Random;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 按照步骤执行的业务逻辑类
*/
public class Wizard {
private Random rand = new Random(System. currentTimeMillis());
//第一步
private int first(){
 System. out.println(" 执行第一个方法...");
 return rand.nextInt(100);
 }
//第二步
private int second(){
 System. out.println(" 执行第二个方法...");
 return rand.nextInt(100);
 }
//第三个方法
private int third(){
 System. out.println(" 执行第三个方法...");
 return rand.nextInt(100);
 }
//软件安装过程
public void installWizard(){
 int first = this.first();
 //根据first返回的结果,看是否需要执行second
 if(first>50){
 int second = this.second();
 if(second>50){
 int third = this.third();
 if(third >50){
 this.first();
 }
 }
 }
 }
}

 三个步骤的访问权限修改为 private,同时把 installeWizad 移动的 Wizard 方法中,这样 Wizard 类就 对外只公布了一个 public 方法,类的高内聚特定显示出来了。我们再来看 InstallSoftware 源码:

package com.cbf4life.common4;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 业务组装类,负责调用各个步骤
*/
public class InstallSoftware {
public void installWizard(Wizard wizard){
 //不废话,直接调用
 wizard.installWizard();
 }
}

 Client 类没有任何改变,就不在拷贝了,这样我们的程序就做到了弱耦合,一个类公布越多的 public 属性或方法,修改的涉及面也就越大,也就是变更引起的风险就越大。因此为了保持朋友类间的距离,你 需要做的是:减少 public 方法,多使用 private、package-private(这个就是包类型,在类、方法、变量 前不加访问权限,则默认为包类型)protected 等访问权限,减少非 static 的 public 属性,如果成员变量 或方法能加上 final 关键字就加上,不要让外部去改变它。
 是自己的就是自己的。在项目中有一些方法,放在本类中也可以,放在其他类中也没有错误,那怎么 去衡量呢?你可以坚持这样一个原则: 如果一个方法放在本类中,即不增加类间关系,也对本类不产生负 面影响,就放置在本类中。
 谨慎使用 Serializable。实话说,这个问题会很少出现的,即使出现也会马上发现问题。是怎么回事呢? 举个例子来说,如果你使用 R M I 的方式传递一个对象 VO( Va lu e Object),这个对象就必须使用 Serializable 接口,也就是把你的这个对象进行序列化,然后进行网络传输。突然有一天,客户端的 VO 对象修改了一个 属性的访问权限,从 private 变更为 public 了,如果服务器上没有做出响应的变更的话,就会报序列化失败。 这个应该属于项目管理范畴,一个类或接口客户端变更了,而服务端没有变更,那像话吗?!
 迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高,其要求 的结果就是产生了大量的中转或跳转类,类只能和朋友交流,朋友少了你业务跑不起来,朋友多了,你项 目管理就复杂,大家在使用的时候做相互权衡吧。
不知道大家有没有听过这样一个理论:“任何 2 个素不相识的人中间最多只隔着 6 个人,即只用 6 个人 就可以将他们联系在一起”,这个理论的学名叫做“六度分离”,应用到我们项目中就是说我和我要调用的 类之间最多有 6 次传递,呵呵,这只能让大家当个乐子来看,在实际项目中你跳两次才访问到一个类估计 你就会想办法了,这也是合理的,迪米特法则要求我们类间解耦,但是解耦是有限度的,除非是计算机的 最小符号二进制的 0 和 1,那才是完全解耦,我们在实际的项目中时,需要适度的考虑这个法则,别为了套 用法则而做项目,法则只是一个参考,你跳出了这个法则,也不会有人判你刑,项目也未必会失败,这就 需要大家使用的是考虑如何度量法则了。(转自24种设计模式)
上一篇文章      下一篇文章      查看所有文章
加:2015-04-05 22:06:35  更:2017-05-15 08:43:04 
 
  Java 最新文章
初入山门,需记门规
java 操作本地数据库 mysql
spring boot 整合 mybatis
单表(SSM、SpringBoot、SpringCloud、Free
Mybatis框架中Mapper动态代理方式
IDEA报错:Error starting ApplicationCont
SSH框架中session问题
Day 3 : 运算符和表达式
Web Service中的几个重要术语
Spring源码分析——资源访问利器Resource之
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 三丰软件 开发 中国文化 网文精选 阅读网 看图 日历 万年历 2018年8日历
2018-8-16 4:57:51
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库