让你彻底搞懂迪米特原则在代码中究竟是如何体现的

前言

说到迪米特原则,后面总能跟上一两句,“最少知道原则,一个类对另一个类知道的越少越好。” 今天主要从代码实例中寻找迪米特的身影,综合实例来看迪米特什么时候适用?迪米特的优缺点?是不是符合迪米特原则的代码就是优质代码?带着这几个问题,我们下面开始探讨。

迪米特

迪米特法则(Law of Demeter),如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身
  • 被当做方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 该对象的任何组件

综上所述,将方法的调用保持在界限内,不去调用超出界限范围的方法,就符合了迪米特原则。

如果我们在探讨过程中遇到问题了,就回头看看迪米特法则的定义。


代码实例

我将演示4个例子,读者可以思考这其中哪些例子符合迪米特原则?哪些不符合?说说你的判断标准以及原因?(欢迎在评论区交流讨论,碰撞出激烈的火花)

demo1

Client端

public class client {
    public static void main(String[] args) {
        Station station = new Station();
        Thermometer thermometer = station.getThermometer();
        System.out.println(thermometer.getTemperature());
    }
}

Station气象站

public class Station {
    public Thermometer getThermometer() {
        return new Thermometer();
    }
}

Thermometer 温度计

public class Thermometer {
    public double getTemperature() {
        return 10;
    }
}

demo2

Client端

public class Client {
    public static void main(String[] args) {
        Station station = new Station();
        double temperature = station.getTemperature();
        System.out.println(temperature);
    }
}

Station气象站

public class Station {
    public double getTemperature() {
        Thermometer thermometer = new Thermometer();
        return thermometer.getTemperature();
    }
}

Thermometer 温度计

public class Thermometer {
    public double getTemperature() {
        return 10;
    }
}

demo3

Client端

public class Client {
    public static void main(String[] args) {
        Station station = new Station();
        System.out.println(station.getTermomoter().getTemperature());
    }
}

Station气象站

public class Station {
    public Thermometer getThermometer() {
        return new Thermometer();
    }
}

Thermometer 温度计

public class Thermometer {
    public double getTemperature() {
        return 10;
    }
}

demo4

Client端

public class Client {
    public static void main(String[] args) {
        System.out.println(new Client().getTemp());
    }

    public double getTemp() {
        Station station = new Station();
        Thermometer thermometer = station.getThermometer();
        return getTempHelper(thermometer);
    }

    public double getTempHelper(Thermometer thermometer) {
        return thermometer.getTemperature();
    }
}

Station气象站

public class Station {
    public Thermometer getThermometer(){
        return new Thermometer();
    }
}

Thermometer 温度计

public class Thermometer {
    public double getTemperature() {
        return 10;
    }
}

揭秘demo面纱

经过分析4个demo,哪些符合迪米特原则呢?且听我慢慢分析,既然是分析,就一定要有理有据,下面我会结合各实例的类图和代码对照进行分析说明。

demo1

查看代码生成的类图我们可以看到 Client 直接和 Station 和 Thermometer 两个类有直接关系,一个类对两个类产生直接关联了就一定不符合迪米特原则吗?且慢,我们要结合代码分析 Client 是否需要和这两个类产生直接关联,我们可以看到 Client 最终的目的只有一个,就是获取温度。目的有一个,但却对两个类产生直接关联,真的有必要吗?我们完全可以通过 Station (气象站)去获取温度,不必直接和 Thermometer(温度计)产生直接的关联。结合定义来看,就是一个类需要调用另一个类的方法的话,可以通过第三者转发这个调用。这里的第三者就是 Station。所以,可以很容易的得出结论,demo1并不符合迪米特原则。

demo2

查看类图发现 Client 只和 Station 产生了直接关联,符合上面我们说的定义,通过第三者(Station)转发这个调用(Client 与 Thermometer 的调用),是典型的符合迪米特原则的例子。

demo3

我们发现,demo3的类图和 demo2类图的类间关系完全一致。那是不是可以由此得出结论,demo3也符合迪米特原则呢?且慢,我们可以看到demo3是链式编程,Client 端中没有显示声明 Thermometer 类的对象,而是隐式的通过 station 调用获取温度计方法返回的 Thermometer 对象调用其中的方法。这种情况如何界定是否符合迪米特原则呢?查看类图发现 Client 和 Thermometer 并没有直接关联,但通过代码可得出,通过 station 对象调用的方法返回的对象进行调用 Thermometer 的方法,所以 Client 还是和 Station 和 Thermometer 有直接关联的,只是没有显示声明而已。结论:demo3 违反了迪米特原则。

demo4

查看类图发现 Client 与 Station类 和 Thermometer类有直接的关系,那是不是可以得出…,真相往往不是这么简单(托眼镜),看到这版例子,是不是想骂上一句,这不是脱裤子**,明明一个方法就可以完成,非要拆成两个方法去调用。先说结论:demo4是符合迪米特原则的,在分析问题卡住的时候,我们不妨回头看看原则的定义是怎么说的,一个类需要调用另一个类的某个方法的话,可以通过第三者转发这个调用。在 demo2中,第三者是 Station,通过 Station 类进行转发了调用。我们分析定义来看,这个第三者指的是什么?在demo2中,第三者是类,而在demo4里,第三者是方法,通过方法转发了调用,一个方法中只调用了一个类的成员方法。我们上面有说到,就任何对象而言,在该对象方法内,符合迪米特原则的调用范围有四点,demo4中也全部符合。通过这种方法转发调用的方式进行解耦。但我们思考一个问题,这样真的有必要吗??


迪米特原则优缺点

迪米特原则的优点,大家都知道,降低类间的耦合关系,毕竟,类间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。

有利一定就有弊,那是不是什么时候都要做到符合迪米特原则?采用迪米特原则会导致更多的“包装”类被制造,以处理和其他组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。

所以,不是任何时刻都要符合迪米特原则,过分的依赖迪米特原则的同时也会带来很多“副作用”。


结论

如何判断代码中是否符合迪米特原则?通过上面分析的经验得出结论:

  • 不能仅看类图,需要代码和类图结合进行分析得出结论
  • 结合原则定义,最终得出的结论一定不能违背概念
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值