设计模式—— 五:迪米特原则

目录

  • 什么是迪米特原则?
  • 迪米特法则的含义
    • 1. 只和朋友交流

      • 不遵循迪米特法则的定义
      • 遵循迪米特法则的定义
    • 2. 朋友间也是有距离的
      • 不遵循迪米特原则的设计
      • 遵循迪米特原则的设计
      • 3. 是自己的就是自己的
      • 4. 谨慎使用Serializable

@

什么是迪米特原则?

迪米特法则来自于1987年美国东北大学(Northeastern University)一个名为“Demeter”的研究项目。迪米特法则又称为最少知识原则(LeastKnowledge Principle, LKP),其定义如下:

迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。

如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度。迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。

迪米特法则的含义

迪米特法则对类的低耦合提出了明确的要求,其包含以下4层含义:

1. 只和朋友交流

迪米特法则还有一个英文解释是:Only talk to your immediate friends(只与直接的朋友通信。)什么叫做直接的朋友呢?每个对象都必然会与其他对象有耦合关系,两个对象之间的 耦合就成为朋友关系,这种关系的类型有很多,例如组合、聚合、依赖等。

以老师要求体育委员清点全班女生为例:

不遵循迪米特法则的定义

5-1:老师要求清点女生类图

老师类:

public class Teacher {
  //老师对学生发布命令,清一下女生
  public void commond(GroupLeader groupLeader){
    List listGirls = new ArrayList(); //初始化女生
    for(int i=0;i<20;i++){
       listGirls.add(new Girl());
    }
  //告诉体育委员开始执行清查任务
   groupLeader.countGirls(listGirls);
   }
}

体育委员类:

public class GroupLeader {
  //清查女生数量
  public void countGirls(List<Girl> listGirls){
    System.out.println("女生数量是:"+listGirls.size());
  } 

}

女生类:

public class Girl {
}

场景类:

public class Client {
   public static void main(String[] args) {
     Teacher teacher= new Teacher();
     //老师发布命令
     teacher.commond(new GroupLeader());
   }
}

运行结果:

女生数量是:20

体育委员按照老师的要求对女生进行了清点,并得出了数量。这个程序有什么问题,首先确定Teacher类有几个朋友类,它仅有一个朋友类—— GroupLeader。为什么Girl不是朋友类呢?Teacher也对它产生了依赖关系呀!朋友类的定义是 这样的:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类,而Girl这个类就是出现在commond方法体内,因此不属于Teacher类的 朋友类。迪米特法则告诉我们一个类只和朋友类交流,但是刚刚定义的commond方法却 与Girl类有了交流,声明了一个List动态数组,也就是与一个陌生的类Girl有了交流, 这样就破坏了Teacher的健壮性。方法是类的一个行为,类竟然不知道自己的行为与其他类 产生依赖关系,这是不允许的,严重违反了迪米特法则。

遵循迪米特法则的定义

现在根据迪米特法则进行改造,去掉Teacher对Girl类的依赖关系。

5-2:修改后的老师要求清点女生类图

修改后的老师类:

public class Teacher {
  //老师对学生发布命令,清一下女生
  public void commond(GroupLeader groupLeader){
  //告诉体育委员开始执行清查任务
  groupLeader.countGirls();
  }
}

修改后的体育委员类:

public class GroupLeader {
  private List<Girl> listGirls; //传递全班的女生进来
  public GroupLeader(List<Girl> _listGirls){
    this.listGirls = _listGirls;
  }
  //清查女生数量
  public void countGirls(){
    System.out.println("女生数量是:"+this.listGirls.size());
  } 

}

修改后的场景类:

public class Client {
  public static void main(String[] args) {
    //产生一个女生群体
    List<Girl> listGirls = new ArrayList<Girl>();
    //初始化女生
    for(int i=0;i<20;i++){
      listGirls.add(new Girl());
    }
    Teacher teacher= new Teacher();
    //老师发布命令
    teacher.commond(new GroupLeader(listGirls));
  }
}

把Teacher中对List的初始化移动到了场景类中,同时在GroupLeader中增加了对Girl的注入,避开了Teacher类对陌生类Girl的访问,降低了系统间的耦合,提高了系统的健壮性。

2. 朋友间也是有距离的

朋友类之间可以交流,但也不能无话不谈。

以安装软件为例:第一步是确认是否安装,第二步确认 License,再然后选择安装目录……这是一个典型的顺序执行动作,具体到程序中就是:调用 一个或多个类,先执行第一个方法,然后是第二个方法,根据返回结果再来看是否可以调用 第三个方法,或者第四个方法。

不遵循迪米特原则的设计

5-3:软件安装过程类图

导向类:
定义步骤方法。

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类:

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();
        }
      }
     } 

    }
}

场景类:

public class Client {
  public static void main(String[] args) {
   InstallSoftware invoker = new InstallSoftware();
   invoker.installWizard(new Wizard());
  } 

}

这个程序有什么问题呢?

Wizard类把太多的方法暴露给InstallSoftware类,两者的朋友关系太亲密了,耦合关系变得异 常牢固。如果要将Wizard类中的first方法返回值的类型由int改为boolean,就需要修改 InstallSoftware类,从而把修改变更的风险扩散开了。因此,这样的耦合是极度不合适的。

遵循迪米特原则的设计

5-4:重构后的软件安装过程类图

修改后的导向类:
在Wizard类中增加一个installWizard方法,对安装过程进行封装,同时把原有的三个 public方法修改为private方法。将三个步骤的访问权限修改为private,同时把InstallSoftware中的方法installWizad移动到 Wizard方法中。通过这样的重构后,Wizard类就只对外公布了一个public方法,即使要修改 first方法的返回值,影响的也仅仅只是Wizard本身,其他类不受影响,这显示了类的高内聚特性。

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();
        }
      }
    }
  } 

}

修改后的InstallSoftware类:

public class InstallSoftware {
  public void installWizard(Wizard wizard){
    //直接调用
    wizard.installWizard();
  }
}

一个类公开的public属性或方法越多,修改时涉及的面也就越大,变更引起的风险扩散 也就越大。因此,为了保持朋友类间的距离,在设计时需要反复衡量:是否还可以再减少 public方法和属性,是否可以修改为private、package-private(包类型,在类、方法、变量前 不加访问权限,则默认为包类型)、protected等访问权限,是否可以加上final关键字等。

3. 是自己的就是自己的

在实际应用中经常会出现这样一个方法:放在本类中也可以,放在其他类中也没有错, 那么就应该坚持这样一个原则:如果一个方法放在本类中,既不增加类间关 系,也对本类不产生负面影响,那就放置在本类中。

4. 谨慎使用Serializable



?? 设计模式—— 四:接口隔离原则

参考:

【1】:《设计模式之禅》
【2】:面向对象设计原则之迪米特法则
【3】:《大话设计模式》
【4】:白话设计——浅谈迪米特法则

原文地址:https://www.cnblogs.com/three-fighter/p/12353205.html

时间: 2024-10-10 22:10:05

设计模式—— 五:迪米特原则的相关文章

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

来源:迪米特法则(LoD)最初是用来作为面向对象的系统设计风格的一种法则,是很多著名系统,如火星登陆软件系统.木星的欧罗巴卫星轨道飞船的软件系统的指导设计原则. 迪米特法则(LoD)又可分为两种:狭义的迪米特法则(LoD)和广义的迪米特法则(LoD). 概念: LOD:LOD,Law Of Demeter 迪米特法则又称最少知识原则,也就是说一个对象应当对其他对象有尽可能少的了解. 狭义的迪米特法则(LoD): 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用. 如果其中的一个

设计模式之6大原则(5)-迪米特法则

迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话.英文简写为: LoD. 迪米特法则可以简单说成:talk only to your immediate friends. 对于面向OOD来说,又被解释为下面几种方式:一个软件实体应当尽可能少的与其他实体发生相互作用.每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位. 迪米特

小菜学设计模式——迪米特原则

背景 本文标题为什么叫小菜学习设计模式,原因是本文内容主要是学习<大话设计模式>时的笔记摘要部分,当然,并不是记录书中小菜的学习过程,这个完全没有意义,而是指本人学习设计模式的成长之旅. 真诚的希望自己能够从一名小菜成长为一名大鸟! 编写的程序应该满足: 1)可维护 2)可扩展 3)可复用 4)够灵活 废话少说,言归正传,设计模式原则之:迪米特原则(最少知识原则) 书面理解 迪米特原则:如果两个类不必彼此直接通信,那么这两个类就应当发生直接的相互作用.如果其中一个类需要调用另一个类的某一个方法

《大话设计模式》:迪米特原则

复习一下之前提到的几个原则: 单一职责:就一个类而言,应该仅有一个引起它变化的原因. 开放-封闭:软件实体(类,模块,函数等等)应该可以扩展,但是不可修改. 依赖倒转:子类型必须能够替换掉他们的父类型. 下面要介绍的是迪米特原则,也叫最少知识原则. 这些原则的提出是为了实现面向对象的几个好处:可维护.可扩展.可复用.灵活性好 迪米特原则 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用. 其根本思想是强

设计模式六大原则(5)——迪米特原则

定义:一个对象应该对其他对象保持最少的了解. 问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大. 解决方案:尽量降低类与类之间的耦合. 自从我们接触编程开始,就知道了软件编程的总原则:低耦合.高内聚.无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率.低耦合的优点不言而喻,是怎样编程才能做到低耦合呢? 迪米特法则又叫最少知道原则,最早是1987年由美国Norigheastern University的lan Holl

迪米特原则与接口隔离原则

强调组件的封装性和信息隐藏的功能. 封装的越好,模块间的耦合越小: 隐藏的越好,组件的可用性越好. 在类的结构设计上,每一个类都应当尽量降低成员的访问权限 http://blog.csdn.net/wangjunkg/article/details/3762132 四.接口隔离原则 全称:“Interface Segregation Principle” 说明:使用多个专一功能的接口比使用一个的总接口总要好.从一个客户类的角度来讲:一个类对另外一个类的依赖性应当是建立在最小接口上的.过于臃肿的接

设计模式之六大设计原则

在上篇博文中提到了开放-封闭原则,没有细谈,这次我们来总结一下设计模式的几大原则. 1开放-封闭原则:是指软件实体(类.模块.函数等)应该可以扩展,但是不可修改. 对原则的理解:开闭原则是最具有理想主义色彩的一个原则,它是面向对象设计的终极目标,下面所要介绍的几个原则可以看成是为了符合开闭原则所作的努力和解决办法.对于开闭原则通俗的理解就是,能不改就不改,能少改尽可能的少改.周所周知,物质是运动的,世界是变化的,想要让一个事物永恒不变是不可能的,所以要想让软件绝对符合开闭原则是不可能的. 2单一

【小话设计模式】面向对象设计原则

1.单一职责原则 单一职责原则的核心思想就是:系统中的每一个对象都应该只有一个单独的职责,而所有对象所关注的就是自身职责的完成.英文缩写SRP  Single Responsibility Principle 单一职责原则-->"高内聚,低耦合",每个类应该只有一个职责,此外只能提供一种功能,而引起类变化的原因应该只有一个.在设计模式中,所有的设计模式都遵循这一原则. 优点: 可以降低类的复杂度: 提高类的可读性,提高系统的可维护性: 变更引起的风险降低. 2.里氏替换原则 里氏

设计模式小结——六大设计原则

设计模式是一套由软件界前辈们总结出的可以反复使用的编程经验,旨在提高代码的可重用性,提高系统的可维护性,以及解决一系列复杂问题.设计模式包括6大设计原则和23种种设计模式.6大设计原则:单一职责原则SRP 应该有却仅有一个原因引起类的变更,即类最好只实现一种功能.高内聚. 单一职责的实现方式是一个职责一个接口. 单一职责适用于类和接口,同样适用于方法,一个方法也应该只做好一件事.里氏替换原则LSP 所有能使用父类的地方必须能透明地使用其子类的对象. 子类必须完全实现父类的方法,如果子类不能完整实