细说设计模式七大原则(5):迪米特法则

基本介绍

英文名:Law of Demeter,LoD

别名:最少知识原则 Least Knowledge Principle,LKP

迪米特法则法则定义如下:

  1. 一个对象应该对其他对象保持最少的了解

  2. 类与类关系越密切,耦合度越大

  3. 迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的 public 方法,不对外泄露任何信息

  4. 迪米特法则还有个更简单的定义:只与直接的朋友通信(Only talk to your immediate friends)

直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

典型的设计模式中介者模式门面模式

应用实例

【例1】打印学生列表

  1. 班级类主要由一个ID和班级名称、一个学生列表, 另外还提供一个打印学生列表的Print()方法。
import java.util.ArrayList;
import java.util.List;

public class MClass {
    public int id;
    public String className;
    public List<Student> students = new ArrayList<>();
    
    public void print(){
        for (Student stu : students) {
            System.out.println("stu id:" + stu.id + " stu name" + stu.studentName);
        }
    }
}
  1. 学生类主要就由ID和学生姓名组成
public class Student {
    public int id;
    public String studentName;
}
  1. School 主要构成同样, 另外也包含了一个Pirnt方法, 他负责打印班级名称和学生名称
import java.util.ArrayList;
import java.util.List;

public class School {
    public int id;
    public String schoolName;
    public List<MClass> mClasses = new ArrayList<>();

    public void print(){
        System.out.println("school id:" + id + "school name:" + schoolName);
        for (MClass mClass : mClasses) {
            System.out.println("class id:" + mClass.id + 
                               "class name:" + mClass.className);

            List<Student> students = mClass.students;
            for (Student stu : students) {
                System.out.println("student id:" + stu.id + 
                                   "student name:" + stu.studentName);
            }
        }
    }
}

现在这个设计的主要问题出在School中,根据迪米特法则,只与直接的类发生通信,而Student类并不是School类的直接关系(以局部变量出现的耦合不属于直接关系),从逻辑上讲学校只与他的班级耦合就行了,与班级的学生并没有任何联系,

这样设计显然是增加了不必要的耦合。按照迪米特法则,应该避免类中出现这样非直接关系的耦合。修改后的代码如下:

import java.util.ArrayList;
import java.util.List;

public class School {
    public int id;
    public String schoolName;
    public List<MClass> mClasses = new ArrayList<>();

    public void print(){
        System.out.println("school id:" + id + "school name:" + schoolName);
        for (MClass mClass : mClasses) {
            System.out.println("class id:" + mClass.id +
                               "class name:" + mClass.className);
        mClass.print();
        }
    }
}

修改后,调用班级打印学生名称的方法,学校直接调用来打印,从而避免了与班级的学生发生耦合。

【例2】咖啡机生产咖啡

咖啡机类:

class CoffeeMachine {
    public void addCoffeeBean() {
        System.out.println("添加咖啡豆");
    }

    public void addWater() {
        System.out.println("添加水");
    }

    public void makeCoffee() {
        System.out.println("制作咖啡");
    }
}

人类:

class Person {
    public void makeCoffee(CoffeeMachine coffeeMachine) {
        coffeeMachine.addCoffeeBean();
        coffeeMachine.addWater();
        coffeeMachine.makeCoffee();
    }
}

人类关心的事情仅仅是让咖啡机制作咖啡,并不关系咖啡是如何制作的,提供较多的开放方法增加了两个类之间的耦合程度,不利于咖啡机类的扩展,假如我们改进了咖啡机的制作工艺,可以自动地加牛奶,这时候,用户需要修改自己地代码。所以我们要减少不必要的联系,实际上也就减少了不必要的麻烦。

修改咖啡机类为仅仅对外暴露一个make方法用于制作咖啡,用户仅仅需要调用这个方法就可以制作咖啡。

咖啡机类:

class CoffeeMachine {
    private void addCoffeeBean() {
        System.out.println("添加咖啡豆");
    }

    private void addWater() {
        System.out.println("添加水");
    }

    private void makeCoffee() {
        System.out.println("制作咖啡");
    } 
    public void make() {
            addCoffeeBean();
            addWater();
            makeCoffee();
    }
}

人类:

class Person {
    public void makeCoffee(CoffeeMachine coffeeMachine) {
        coffeeMachine.make();
    }
}

迪米特法则的目的,是把我们的类变成一个个“肥宅”。

迪米特法则的核心观念就是类间解耦,弱耦合。迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。只有弱耦合了之后,类的复用才可以提高,类变更的风险才可以减低。但解耦是有限度的,除非是计算机的最小单元–二进制的0和1,否则都是存在耦合的。

但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系,例如本例中,总公司就是通过分公司这个“中介”来与分公司的员工发生联系的。

过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

迪米特法则细节

  1. 迪米特法则的核心是降低类之间的耦合

  2. 但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系, 并不是要求完全没有依赖关系

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值