zoukankan      html  css  js  c++  java
  • 05.迪米特原则 (LOD)

    LOD全称

    LOD, Law of Demeter, 迪米特原则 or LKP, Least Knowledge Principle, 最少知识原则

    定义

    一个对象应该对其他对象有最少的了解。一个类应该对自己需要耦合或调用的类知道的最少,类的内部如何实现与调用者或者依赖者没有关系,调用者或者依赖者只需知道它需要的方法即可。

    只与直接的朋友发生通信。

    优点

    1. 降低类之间的耦合度,提高了模块的相对独立性
    2. 耦合度降低,从而提高了类的可重用率和系统的扩展性

    缺点

    • 过度使用迪米特原则,会产生大量的中介类,导致系统的复杂度提高。在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰

    实现

    • 问题由来: 类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大

    • 解决方案: 尽量降低类与类之间的耦合

    1. 需强调

      • 从依赖者的角度来说,只依赖应该依赖的对象。
      • 从被依赖者的角度说,只暴露应该暴露的方法。
    2. 需注意

      • 在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。
      • 在类的结构设计上,尽量降低类成员的访问权限。
      • 在类的设计上,优先考虑将一个类设置成不变类。
      • 在对其他类的引用上,将引用其他对象的次数降到最低。
      • 不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。
      • 谨慎使用序列化(Serializable)功能。

    实例

    例子:有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工ID。先来看一下违反迪米特法则的设计。

    // 总公司员工
    class Employee {
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    
    // 分公司员工
    class SubEmployee {
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    
    // 子公司管理
    class SubCompanyManager {
        public List<SubEmployee> getAllEmployee() {
            List<SubEmployee> list = new ArrayList<>();
            for (int i = 1; i < 100; i++) {
                SubEmployee subEmployee = new SubEmployee();
                // 给分公司人员顺序分配一个ID
                subEmployee.setId("分公司" + i);
                list.add(subEmployee);
            }
            return list;
        }
    }
    
    // 总公司管理
    class CompanyManager {
        public List<Employee> getAllEmployee() {
            List<Employee> list = new ArrayList<>();
            for (int i = 1; i < 30; i++) {
                Employee employee = new Employee();
                // 给总公司人员顺序分配一个ID
                employee.setId("总公司" + i);
                list.add(employee);
            }
            return list;
        }
    
        public void printAllEmployee(SubCompanyManager subCompanyManager) {
            // 分公司员工
            List<SubEmployee> subEmployeeList = subCompanyManager.getAllEmployee();
            for (SubEmployee subEmployee : subEmployeeList) {
                System.out.println(subEmployee.getId());
            }
    
            // 总公司员工
            List<Employee> employeeList = getAllEmployee();
            for (Employee employee : employeeList) {
                System.out.println(employee.getId());
            }
        }
    }
    
    public class LODClient {
        public static void main(String[] args) {
            CompanyManager companyManager = new CompanyManager();
            companyManager.printAllEmployee(new SubCompanyManager());
        }
    }
    

    问题出现在CompanyManager类,根据迪米特法则,只与直接的朋友发生通信。而SubEmployee类并不是CompanyManager类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲总公司只与他的分公司耦合就行了,与分公司的员工并没有任何联系,这样设计显然是增加了不必要的耦合。按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合。修改后的代码如下

    // 总公司员工
    class Employee {
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    
    // 分公司员工
    class SubEmployee {
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    
    // 子公司管理
    class SubCompanyManager {
        public List<SubEmployee> getAllEmployee() {
            List<SubEmployee> list = new ArrayList<>();
            for (int i = 1; i < 100; i++) {
                SubEmployee subEmployee = new SubEmployee();
                // 给分公司人员顺序分配一个ID
                subEmployee.setId("分公司" + i);
                list.add(subEmployee);
            }
            return list;
        }
    
        public void printSubCompany() {
            List<SubEmployee> subEmployeeList = this.getAllEmployee();
            for (SubEmployee subEmployee : subEmployeeList) {
                System.out.println(subEmployee.getId());
            }
        }
    }
    
    // 总公司管理
    class CompanyManager {
        public List<Employee> getAllEmployee() {
            List<Employee> list = new ArrayList<>();
            for (int i = 1; i < 30; i++) {
                Employee employee = new Employee();
                // 给总公司人员顺序分配一个ID
                employee.setId("总公司" + i);
                list.add(employee);
            }
            return list;
        }
    
        public void printAllEmployee(SubCompanyManager subCompanyManager) {
            // 分公司员工
            subCompanyManager.printSubCompany();
    
            // 总公司员工
            List<Employee> employeeList = getAllEmployee();
            for (Employee employee : employeeList) {
                System.out.println(employee.getId());
            }
        }
    }
    
    public class LODClient {
        public static void main(String[] args) {
            CompanyManager companyManager = new CompanyManager();
            companyManager.printAllEmployee(new SubCompanyManager());
        }
    }
    
    

    修改后,为分公司增加了打印人员ID的方法,总公司直接调用来打印,从而避免了与分公司的员工发生耦合。

    总结

    1. 迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。
    2. 过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。
  • 相关阅读:
    nginx proxy_set_header
    nginx minio
    /etc/nginx/sitesenabled
    IDEA从mapper.java或者dao.java跳转到mapper.xml
    htmlwebpackplugin 配置项
    第29天 [js]时间戳转换
    CSS权重值计算
    nginx+keepalived实现高可用负载均衡 繁华
    kali安装 IDEA2020 破解并创建快捷方式
    下载 android source 之repo获取
  • 原文地址:https://www.cnblogs.com/lwcode6/p/13954954.html
Copyright © 2011-2022 走看看