zoukankan      html  css  js  c++  java
  • 六大设计原则--迪米特原则

    5.迪米特法则(Low of Demeter)
    迪米特法则又叫:最少知识原则(Least Knowledge Principle) ,简称LKP
    迪米特原则要求类要小气一点,类只和自己的朋友交流,不和陌生人说话。
    朋友的定义:
    • `1. 当前对象本身this`
    • `2. 以参数的形式传入当前对象方法中的对象`
    • `3. 当前对象的类成员变量`
    • `4. 如果当前对象的类成员变量是一个集合,那么集合中的元素都是朋友`
    • `5. 当前对象所创建的对象`
    迪米特法则的定义:两个类如果不必彼此直接通信,那么这两个类就不应该发生相互作用,如果其中一个类需要调用另一个类的某一个方法的,可以通过第三方转发这个调用。  
    **只和朋友交流**
    举例说明:
    在大学中,有很多的院系,每个院系都有院长,辅导员和学生,院长只和辅导员打交道,而辅导员和学生打交道。因此院长和学生就是陌生人的关系。
    假设院长要找几个学生干活,但是学生只听辅导员的,因为他不认识院长。
    设计类:
    public class Student {
    
        public void work() {
            System.out.println("学生干活");
        }
    
    }
    public class Counsellor {
    
        private Student student;
        
        public void makeStudentWork() {
            this.student.work();
        }
        
        public Student getStudent() {
            return student;
        }
        
        public void setStudent(Student student) {
            this.student = student;
        }
    }
    首先我们看如果不使用迪米特原则,那么院长如果找学生干活的话:
    public class President {
    
        public void makeCounsellorWork() {
                Student student = new Student();
                this.counsellor.setStudent(student);
                this.counsellor.makeStudentWork();
            }
        
            public Counsellor getCounsellor() {
                return counsellor;
            }
        
            public void setCounsellor(Counsellor counsellor) {
                this.counsellor = counsellor;
            }
    }
    因为学生不认识院长,只认识辅导员,因此院长首先要找到一个干活的学生,然后还要找到这个学生的辅导员,然后让这个辅导员指挥学生干活:
    public class Traditional {
    
        public static void main(String[] args) {
            President president = new President();
    
            Counsellor counsellor = new Counsellor();
            president.setCounsellor(counsellor);
            president.makeCounsellorWork();
        }
    }
    院长和学生是陌生人,但是在方法内却依赖了学生这个类,这不符合迪米特法则。我们想一下, 如果院长找学生干活的话,那么他应该直接找辅导员,说:给我找两个学生来干个活。
    找学生的事应该辅导员来做,而不是院长找学生。因此我们的方法,应该把找学生这个交给辅导员去做。
    public class Counsellor {
    
        private Student student;
    
        public void makeStudentWork() {
            this.student = new Student();
            this.student.work();
        }
    
        public Student getStudent() {
            return student;
        }
    
        public void setStudent(Student student) {
            this.student = student;
        }
    }
    院长只需要告诉辅导员找个学生干活:
     public void makeCounsellorWork() {
            this.counsellor.makeStudentWork();
        }
    至于辅导员怎么找学生,跟院长没有关系,当学生的方法属性等发生改变时,只需要更改辅导员类,而不需要修改院长这个类。  
    **尽量降低一个类的访问权限, 减少与朋友的交流**
    迪米特法则要求类要小气一点,尽量建少与朋友的交流,也就是尽量少的提供public 方法,转而多使用private, default, protected等方法,尽量使类可以独立的完成自己的任务。
    我们想象一下装软件的过程,在装软件的页面,根据我们的选择,点击下一步跳转不同的页面。我们来实现这个调用:
    /**
     * 假设一个软件,共有四个步骤:
     * 执行流程,当进入安装页面首先调用第一个方法,
     * 然后根据第一个方法的返回值决定调用第二个或者第三个方法。如果调用第二个方法则安装结束,如果调用第三个方法则根据返回结果决定是否调用第四个方法
     * 并结束安装。
     * @author ZhaoShuai
     * @date Create in 2020/4/17
     **/
    public class App {
    
        public int first() {
            System.out.println("开始安装,进行第一步");
            return new Random().nextInt(4);
        }
    
        public void second() {
            System.out.println("调用结束安装方法");
        }
    
        public int third() {
            System.out.println("调用第三个方法");
            return new Random().nextInt(3);
        }
    
        public void four() {
            System.out.println("调用第四个方法");
        }
    
    }
    public class Client {
    
        public static void main(String[] args) {
            App app = new App();
    
            int first = app.first();
            while (first == 1 || first == 0) {
                first = app.first();
            }
    
            System.out.println("第一步返回结果:" + first);
            if (first == 2) {
                app.second();
    
            } else if (first == 3) {
    
                System.out.println("安装进行第二步");
                int third = app.third();
    
                System.out.println("第二步返回结果" + third);
                if (third == 2) {
    
                    System.out.println("进行安装第三步");
                    app.four();
                    app.second();
                }
            }
        }
    }
    方法很简单,我们会发现app类内部的方法,都是public的,而且会按照固定的模式去执行,而这个执行过程交给Client类来管理。也就是让客户端来决定下一步如何调用。
    这种设计中,客户端调用大量的app方法,就会使客户端与app两个类的耦合度过高。这时无论修改app内哪儿个方法的返回值,都需要修改客户端的调用代码返回值。
    根据迪米特法则,我们可以把这个调用过程放进app类里面:
    public class App2 {
    
        public void startRun() {
            int first = this.first();
            while (first == 1 || first == 0) {
                first = this.first();
            }
    
            System.out.println("第一步返回结果:" + first);
            if (first == 2) {
                this.second();
    
            } else if (first == 3) {
    
                System.out.println("安装进行第二步");
                int third = this.third();
    
                System.out.println("第二步返回结果" + third);
                if (third == 2) {
    
                    System.out.println("进行安装第三步");
                    this.four();
                    this.second();
                }
            }
        }
    
        private int first() {
            System.out.println("开始安装,进行第一步");
            return new Random().nextInt(4);
        }
    
        private void second() {
            System.out.println("调用结束安装方法");
        }
    
        private int third() {
            System.out.println("调用第三个方法");
            return new Random().nextInt(3);
        }
    
        private void four() {
            System.out.println("调用第四个方法");
        }
    }
    public class Client2 {
        public static void main(String[] args) {
            App2 app2 = new App2();
            app2.startRun();
        }
    }
    这样设计的意思就是:你已经是一个成熟的软件了,应该可以自己执行安装过程,而客户端只需要点击开始安装按钮,剩下的安装过程全都交给程序内部自己执行,这样设计
    无论app2类内部的方法如何改变,我们都只需要在类内部更改,与外部调用无关。这样就做到了解耦。根据迪米特法则,如果我们确定客户端与app类在同一个包下,由客户端来
    调用app2的安装,那么app2的类应该设计为包访问权限,即: class App2{...} 
    设计原则:
    • `1. 优先考虑设计成不变类final`
    • `2. 如果一个方法放在本类中,既不增加类间关系,也不对本类产生负面影响,那么就放置在本类中`
    • `3. 尽量减少类中的public方法,与接口隔离原则中接口要高内聚思想一样,类也要高内聚`
    • `4. 谨慎使用Serializable,如果使用到了RMI方式传递对象,那么这个对象必须实现Serializable接口`
    迪米特法则的缺陷:  
    迪米特法则要求降低类之间的耦合关系,如果要调用尽量通过第三方调用,但是这样就会导致产生大量的中间第三方类,这个类里的大量方法仅仅只是转发类的调用,没有其他实际意义。这样就会导致类的复杂性增加。
  • 相关阅读:
    APPIUM Android 定位方式
    SQL Server 根据存储过程的结果集创建临时表
    Ubuntu18.04 设置开机自启动服务
    ubuntu-18.04 (各版本镜像下载) 及的环境初始化配置
    CentOS 7 编译安装PHP5.6.31
    Centos7 编译安装 MySQL 5.5.62
    Windows 2008 R2 远程桌面连接记录(客户端IP)
    CentOS crontab定时任务
    CentOS 7 安装MySql 5.5.60
    SQL Server 数据库错误码解释
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/12718047.html
Copyright © 2011-2022 走看看