迪米特法则

什么是迪米特法则

迪米特法则(Law of Demeter, LoD),又被称为最少知识原则,这个原则规定了,一个对象应该对另一个对象有最少的了解,什么又是最少的了解,就是减少一个对象在另一个对象出现的次数,甚至不出现,减少类于类之间的耦合关系。
一个类对另一个类的了解,都是基于其public方法。
迪米特法则还有一个英文解释:Only talk to your immediate friends,只于一个类之间的朋友进行交流。
什么是类于类之间的交流?无非就是一个类中的方法中调用另一个类的方法。
什么是直接朋友?一个类的朋友就是这个类本身、这个类的成员对象、这个对象创建的对象、当前对象的方法参数等等。
参考如下代码,Address,Book,Stuent这些都是Teacher的朋友。

public class Teacher {

    private Address address;

    public void tech(Book book){
        System.out.println(book.getName);
    }

    public Studnet findStudent(){
        return Student();
    }

}

只和朋友交流

如何做到之和朋友类交流,来看一个案例:
老师想让班长去清点一下班级的人数,让我们用代码去实现这个场景;
先看类图:
在这里插入图片描述
代码:


public class Student {
}



public class Teacher {

    void command(Monitor monitor){
        List<Student> listStudent = new ArrayList<>();
        for (int i=0; i<3; i++){
            listStudent.add(new Student());
        }
        monitor.countStudent(listStudent);
    }
}

public class Monitor {

    void countStudent(List<Student> list){
        System.out.println("学生人数:" + list.size());
    }
}

public class Client {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.command(new Monitor());
    }

}

运行结果:
在这里插入图片描述
运行结果很成功,学生人数被统计出来了。
但是这样的设计有什么问题?
首先Teacher类有几个朋友类,只有Monitor类(成员变量),那这里Student类是它的朋友类吗?不是,Student类是在方法中产生的,不是朋友类,但它却出现在了Teacher类中,这就相当于和Teacher类产生了交流,产生了依赖,这样回导致,如果以后Student类发生了改变,Teacher类也得同步参数修改,这是严重不允许的,严重违反迪米特法则。
让我们去修改一下这个类图结构:

在这里插入图片描述


public class Student {
}

public class Monitor {

    private List<Student> list;

    public Monitor(List<Student> list) {
        this.list = list;
    }

    void countStudent(){
        System.out.println("学生人数:" + list.size());
    }
}


public class Teacher {

    void command(Monitor monitor){

        monitor.countStudent();
    }
}


public class Client {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        List<Student> listStudent = new ArrayList<>();
        for (int i=0; i<3; i++){
            listStudent.add(new Student());
        }
        teacher.command(new Monitor(listStudent));
    }

}


观察改进前和改进后的代码有什么区别,改进前,Monitor类需要统计Student类,需要一个List,通过它的上级调用类,也就是Teacher类创建得到,虽然完成了业务,但是却导致Teacher类和它的非朋友类Student产生了交流,以后如果Student类有改动,Teacher类也会跟着改,于是进行修改,把Monitor类和Studnet类的依赖用成员变量的方式进行依赖,通过构造方法进行传递,这样Teacher类就可以不用和Studnet类进行交流,就能完成业务了。

朋友之间交流也不要太密切

迪米特法则中规定,一个类中,只与这个类的朋友进行联系,说简单点,就是一个类的方法中,如果一个类不是这个类的成员变量、函数参数、或者这个类通过方法创建出来的,最好不要出现在这个方法中。
但是,即使这个某个类是这个类的朋友,也应该尽可能的减少交流,也就是调用。
比如说,我们的电脑要安装一个软件,是不是要点击软件包,然后一直点下一步,如果某一步失败,后续的步骤也不能继续往下执行了。
来用代码表示是什么样的?

public class Install {

    int checkDir(){
        System.out.println("检查目录");
        return 1;
    }

    int checkSpace(){
        System.out.println("检查空间");
        return 1;
    }

    int install(){
        System.out.println("安装软件");
        return 1;
    }


}

public class Computer {
    private Install install;

    public Computer(Install install) {
        this.install = install;
    }

    void installSoftWare(){
        //检查目录是否存在
        int i = install.checkDir();
        if (i==1){
            //检查空间是否足够
            int i1 = install.checkSpace();
            if (i1==1){
                int install = this.install.install();
                if (install==1){
                    System.out.println("安装成功");
                    return;
                }else {
                    System.out.println("安装失败");
                    return;
                }
            }
        }
        System.out.println("安装失败");

    }

}

仔细看Computer类安装的方法,它和之间的朋友类Install进行交流,每次步骤返回1,代表成功,就进行下一步。这样的代码也许能模拟这个业务,但是它有什么问题?我们得考虑以后代码变动的风险,如果以后,每个安装步骤的返回值,不在返回1代表成功,而是布尔类型的true代表成功,这样回导致Computer类所有对这些方法调用的地方都得修改。
为了改进这种情况,我们需要对类结构进行修改,如下:

public class Install {

    private int checkDir(){
        System.out.println("检查目录");
        return 1;
    }

    private int checkSpace(){
        System.out.println("检查空间");
        return 1;
    }

    private int install(){
        System.out.println("安装软件");
        return 1;
    }

    public void installSoftForComputer(){
        int i = checkDir();
        if (i==1){
            //检查空间是否足够
            int i1 = checkSpace();
            if (i1==1){
                int install = install();
                if (install==1){
                    System.out.println("安装成功");
                    return;
                }else {
                    System.out.println("安装失败");
                    return;
                }
            }
        }
        System.out.println("安装失败");
    }

}

public class Computer {
    private Install install;

    public Computer(Install install) {
        this.install = install;
    }

    void installSoftWare(){
        //检查目录是否存在
        install.installSoftForComputer();

    }

}

看到改变前后的区别了吗?我把之前computer需要一个一个去调用的方法,封装在了Install一个public方法中,并且把每个安装步骤都设置为私有,这样有什么好处?我们减少了类与类之间的交流,同时也减少了它们变更带了的风险,以后Install类的变更,比如变更返回类型,那也只对Install内部有影响,这就是我们常说的高内聚!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

i进击的攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值