设计模式原则5----迪米特法则

个人博客:打开链接

迪米特法则定义

迪米特法则(Law of Demeter, LoD)也称为最少知识原则(Least Knowledge Principle, LKP),一个对象应该对其他对象有最少的了解。通俗来讲,一个类应该对自己需要耦合或调用的类知道的最少。我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关心。

1.只和朋友交流

迪米特法则的英文解释是,Only talk to your immediate friends,只和直接的朋友通信。每个对象都必然会与其他对象有耦合关系,两个对象之间的耦合就成为朋友关系,这种关系的类型有很多,例如组合、聚合、依赖等。
例如,老师让体育委员清点一下班里女生到齐没有。其UML图为:
这里写图片描述
老师类:

public class Teacher{
    //老师对学生发布命令,清点一下女生
    public void commond(GroupLeader groupLeader){
        List<Girl> listGirls = new ArrayList();
        //初始化女生
        for(int i = 0; i < 20; i++){
            listGirls.add(new Girl());
        }
        //告诉体育委员开始执行清查任务
        groupLeader.countGirls(listGirls);
    }
}

体育委员类:

public class GroupLeader{
    //清查女生数量
    public void countGirls(List<Girl> listGirls){
        System.out.println("女生数量是:" + listGirls.size());
    }
}

女生类:

public class Girl {
    //女生相关属性

}

场景类:

public class Client{
    public static void main(String[] args){
        Teacher teacher = new Teacher();
        //老师发布命令
        teacher.commond(new GroupLeader());
    }
}

运行结果:

女生数量是:20

然而,我们发现,体育老师和不相关的Girls产生了依赖,这是违反迪米特法则的。朋友类的定义是,出现在成员变量、方法的输入输出参数中的类称为成员朋友,而出现在方法体内部的类不属于朋友类,而Girl这个类就是出现在commond方法体内,因此不属于Teacher类的朋友类。迪米特法则告诉我们一个类只和朋友交流,但是我们刚才定义的commond方法却和Girl类有了交流,声明了一个List < Girls >数组,也就是与一个陌生的类Girl有了交流,这就破坏了Teacher的健壮性。方法是类的一个行为,类竟然不知道自己的行为与其他类产生依赖关系,这是不允许的,严重违反了迪米特法则。
我们做一下调整,UML类图为:
这里写图片描述
修改后的体育老师类:

public class Teacher {
    //老师对学生发出命令,清点一下班里女生
    public void commond(GroupLeader groupLeader){
        //老师对体育委员发出命令,清点一下班里女生
        groupLeader.countGirls();
    }
}

修改后的体育委员类:

public class GroupLeader {
    private List<Girl> listGirls;
    //传递全班女生进来
    public GroupLeader(List<Girl> _listGirls){
        this.listGirls = _listGirls;
    }
    //清查女生数量
    public void countGirls(){
        System.out.println("女生数量是:" + this.listGirls.size());
    }
}

修改后的场景类:

public class Client {
    public static void main(String[] args){
        //产生一个女生群体
        List<Girl> listGirls = new ArrayList<Girl>();
        //初始化女生
        for(int i = 0; i < 20; i++){
            listGirls.add(new Girl());
        }
        Teacher teacher = new Teacher();
        //老师发布命令
        teacher.commond(new GroupLeader(listGirls));
    }
}

这样避开了Teacher类对陌生类Girl的直接访问,降低了系统间的耦合,提高了系统的健壮性。

距离产生美,朋友间也是有距离的

比如说对于一个软件安装过程,假设有三步,其UML类图为:
这里写图片描述
导向类:

public class Wizard {
    private Random rand = new Random(System.currentTimeMillis());
    // first step
    public int first(){
        System.out.println("first function exe...");
        return rand.nextInt(100);
    }
    //second step
    public int second(){
        System.out.println("second function exe...");
        return rand.nextInt(100);
    }
    //third step
    public int third(){
        System.out.println("third function exe...");
        return rand.nextInt(100);
    }

InstallSoftware类:

public class InstallSoftware {
    public void installWizard(Wizard wizard){
        int first = wizard.first();
        //根据first返回结果,看是否需要执行second
        if(first > 50){
            int second = wizard.second();
            if(second > 50){
                int third = wizard.third();
                if(third > 50){
                    wizard.first();
                }
            }
        }
    }
}

场景类:

public class Client {
    public static void main(String[] args){
        InstallSoftware = invoker = new InstallSoftware();
        invoker.installWizard(new Wizard());
    }
}

对于上述设计,Wizard类把太多的方法暴露给InstallSoftware类,两者的朋友关系太亲密了,耦合关系变得异常牢固。如果要将Wizard类中的first方法返回值的类型由int改为boolean,就需要修改InstallSoftware类,从而把修改变更的风险扩散开了。因此,这样的耦合是季度不合适的,对其进行重构:
这里写图片描述
在Wizard类中增加一个installWizard方法,对安装过程进行封装,同时把原有的三个public方法修改为private方法。
修改后的导向类:

public class Wizard {
    private Random rand = new Random(System.currentTimeMillis());
    // first step
    private int first(){
        System.out.println("first function exe...");
        return rand.nextInt(100);
    }
    //second step
    private int second(){
        System.out.println("second function exe...");
        return rand.nextInt(100);
    }
    //third step
    private int third(){
        System.out.println("third function exe...");
        return rand.nextInt(100);
    }
    //软件安装过程
    public void installWizard(Wizard wizard){
        int first = wizard.first();
        //根据first返回结果,看是否需要执行second
        if(first > 50){
            int second = wizard.second();
            if(second > 50){
                int third = wizard.third();
                if(third > 50){
                    wizard.first();
                }
            }
        }
    }

}

修改后的InstallSoftware类:

public class InstallSoftware {
    public void installWizard(Wizard wizard) {
        // 直接调用
        wizard.installWizard();
    }
}

将三个步骤的访问权限修改为private,同时把InstallSoftware中的方法installWizard移动到Wizard方法中,通过这样重构,Wizard类就只对外公布了一个public方法,即使再修改first方法的返回值,影响的也仅仅只是Wizard本身,其他类不受影响,这显示了高内聚的特性。

3. 是自己的就是自己的

如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

4. 小结

迪米特法则的核心观念是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

勤奋的凯尔森同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值