开发原则六:迪米特法则LOD

1987年秋天由美国Northeastern University的Ian Holland提出,被UML的创始者之一Booch等普及。后来,因为在经典著作《 The Pragmatic Programmer》而广为人知。

迪米特法则

也被称为最少知识原则(Least Knowledge Principle),是面向对象设计中的一条原则。它强调了类之间的低耦合和高内聚。根据迪米特法则,一个对象应该尽量减少与其他对象之间的交互,只与直接的朋友进行通信。这意味着在设计中,一个类应该尽可能少地依赖其他的类,而是通过与其他类的合作来实现某个功能。这样可以降低类之间的耦合度,使得代码更加灵活、可维护和可扩展。

迪米特法则要求:

对象对其他对象有限的了解:一个对象只应该与其直接朋友进行通信,不应该调用非直接朋友的方法。
不暴露对象的内部信息:一个对象不应该将自己的内部信息暴露给其他对象,而是通过提供公共接口来与其他对象进行交互。
最小化对象之间的交互:一个对象在设计时,应该尽量减少与其他对象之间的交互,只关注与自身相关的事务。
迪米特法则能够提高代码的可维护性和可复用性,减少代码的耦合度,同时也符合面向对象设计的封装思想。

迪米特法则定义

一个对象应该对其他对象有限的了解,只与直接朋友进行通信。直接朋友包括以下几类:
该对象本身
以参数形式传入到该对象方法中的对象
该对象所创建的对象
该对象的成员变量引用的对象
根据迪米特法则,当我们设计一个对象时,应该尽量避免让该对象调用非直接朋友的方法。这样可以降低类之间的依赖关系,提高系统的可维护性和灵活性。

迪米特法则的好处

减少耦合度:通过限制对象之间的交互,可以减少类之间的依赖关系,使得系统更加松散耦合。
提高模块化:每个对象只和其直接朋友进行交互,使得每个模块的职责更加明确,易于理解和修改。
提升可维护性:减少了对象之间的依赖,修改一个对象不会对其它对象造成意外影响,从而减少了代码的风险。

迪米特法则实际应用:

尽量将逻辑封装在对象的内部,通过提供公共接口进行通信。
避免链式调用,尽量直接调用自身或成员变量引用的对象的方法。
少使用全局变量和单例模式,减少对象之间的全局状态共享。
使用依赖注入等技术来降低对象之间的耦合度。

案例实践一:

老师让班长清点全班同学的人数。这个例子中总共有三个类:老师Teacher、班长GroupLeader和学生Student。

public interface ITeacher {
    void command(IGroupLeader groupLeader);
}
public class Teacher implements ITeacher{
    @Override
    public void command(IGroupLeader groupLeader) {
        // 全班同学
        List<Student> allStudent = new ArrayList<>();
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        // 班长清点人数
        groupLeader.count(allStudent);
    }
}
**
 * 班长类
 */
public interface IGroupLeader {
    // 班长清点人数
    void count(List<Student> students);
}
/**
 * 班长类
 */
public class GroupLeader implements IGroupLeader{
    /**
     * 班长清点人数
     * @param students
     */
    @Override
    public void count(List<Student> students) {
        // 班长清点人数
        System.out.println("上课的学生人数是: " + students.size());
    }
}
/**
 * 学生类
 */
public interface IStudent {
}
/**
 * 学生类
 */
public class Student implements IStudent {
}
/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 老师类
        ITeacher wangTeacher = new Teacher();
        // 班长
        IGroupLeader zhangBanzhang = new GroupLeader();
        wangTeacher.command(zhangBanzhang);
    }
}

在这个例子中,我们的Teacher有几个朋友?两个,一个是GroupLeader,它是Teacher的command()方法的入参;另一个是Student,因为在Teacher的command()方法体中使用了Student
那么Teacher有几个是直接的朋友?按照直接的朋友的定义
只有GroupLeader是Teacher的直接的朋友。
Teacher在command()方法中创建了Student的数组,和非直接的朋友Student发生了交流,所以,上述例子违反了迪米特法则。方法是类的一个行为,类竟然不知道自己的行为与其他的类产生了依赖关系,这是不允许的,严重违反了迪米特法则!

public interface ITeacher {
    void command(IGroupLeader groupLeader);
}
public class Teacher implements ITeacher {
    @Override
    public void command(IGroupLeader groupLeader) {
        // 班长清点人数
        groupLeader.count();
    }
}
/**
 * 班长类
 */
public interface IGroupLeader {
    // 班长清点人数
    void count();
}
/**
 * 班长类
 */
public class GroupLeader implements IGroupLeader {
    private List<Student> students;
    public GroupLeader(List<Student> students) {
        this.students = students;
    }
    /**
     * 班长清点人数
     */
    @Override
    public void count() {
        // 班长清点人数
        System.out.println("上课的学生人数是: " + students.size());
    }
}
/**
 * 学生类
 */
public interface IStudent {
}
/**
 * 学生类
 */
public class Student implements IStudent {
}
/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 老师类
        ITeacher wangTeacher = new Teacher();
        List<Student> allStudent = new ArrayList(10);
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        // 班长
        IGroupLeader zhangBanzhang = new GroupLeader(allStudent);
        wangTeacher.command(zhangBanzhang);
    }
}

这样修改后,每个类都只和直接的朋友交流,有效减少了类之间的耦合

案例实践二

一个人用咖啡机煮咖啡的过程,例子中只有两个类,一个是人,一个是咖啡机。
首先是咖啡机类CoffeeMachine,咖啡机制作咖啡只需要三个方法:1.加咖啡豆;2.加水;3.制作咖啡:

/**
 * 咖啡机抽象接口
 */
public interface ICoffeeMachine {
    //加咖啡豆
    void addCoffeeBean();
    //加水
    void addWater();
    //制作咖啡
    void makeCoffee();
}
/**
 * 咖啡机实现类
 */
public class CoffeeMachine implements ICoffeeMachine{
    //加咖啡豆
    public void addCoffeeBean() {
        System.out.println("放咖啡豆");
    }
    //加水
    public void addWater() {
        System.out.println("加水");
    }
    //制作咖啡
    public void makeCoffee() {
        System.out.println("制作咖啡");
    }
}
/**
 * 人, 制作咖啡
 */
public interface IMan {
    /**
     * 制作咖啡
     */
    void makeCoffee();
}
/**
 * 人制作咖啡
 */
public class Man implements IMan {
    private ICoffeeMachine coffeeMachine;
    public Man(ICoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }
    /**
     * 制作咖啡
     */
    public void makeCoffee() {
        coffeeMachine.addWater();
        coffeeMachine.addCoffeeBean();
        coffeeMachine.makeCoffee();
    }
}
/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        ICoffeeMachine coffeeMachine = new CoffeeMachine();
        IMan man = new Man(coffeeMachine);
        man.makeCoffee();
    }
}

在这个例子中,CoffeeMachine是Man的直接好友,但问题是Man对CoffeeMachine了解的太多了,其实人根本不关心咖啡机具体制作咖啡的过程。所以我们可以作如下优化:
优化后的咖啡机类,只暴露一个work方法,把制作咖啡的三个具体的方法
addCoffeeBean、addWater、makeCoffee设为私有:

/**
 * 咖啡机抽象接口
 */
public interface ICoffeeMachine {
    //咖啡机工作
    void work();
}
/**
 * 咖啡机实现类
 */
public class CoffeeMachine implements ICoffeeMachine {
    //加咖啡豆
    public void addCoffeeBean() {
        System.out.println("放咖啡豆");
    }
    //加水
    public void addWater() {
        System.out.println("加水");
    }
    //制作咖啡
    public void makeCoffee() {
        System.out.println("制作咖啡");
    }
    @Override
    public void work() {
        addCoffeeBean();
        addWater();
        makeCoffee();
    }
}
/**
 * 人, 制作咖啡
 */
public interface IMan {
    /**
     * 制作咖啡
     */
    void makeCoffee();
}
/**
 * 人制作咖啡
 */
public class Man implements IMan {
    private ICoffeeMachine coffeeMachine;
    public Man(ICoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }
    /**
     * 制作咖啡
     */
    public void makeCoffee() {
        coffeeMachine.work();
    }
}
/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        ICoffeeMachine coffeeMachine = new CoffeeMachine();
        IMan man = new Man(coffeeMachine);
        man.makeCoffee();
    }
}

这样修改后,通过减少CoffeeMachine对外暴露的方法,减少Man对CoffeeMachine的了解,从而降低了它们之间的耦合

你可能感兴趣的:(java,设计模式,迪米特法则,设计模式,设计规范)