# 迪米特法则

迪米特法则为七大设计原则之一。

# 定义

迪米特法则(Law Of Demeter, LoD),也被称为最少知识原则(Least Knowledge Principle, LKP)。

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

# 反面例子

假设:

  • A与B是好朋友,A可以寻找B帮忙
  • B与C也是好朋友,B可以寻找C帮忙
  • 但A发生了一件事情,只有C可以解决,但A不认识C,怎么办呢?

可以肯定的是,需要寻找B来拜托C帮忙,因为B同时是A和C的好朋友。但是该如何实现呢?

首先来看看错误的实现方式

class A {
    constructor(name) {
        this.name = name;
    }
    // A与B是好朋友,所以可以寻找B
    getB(name) {
        return new B(name);
    }
    // 一件难题,只有C可以解决
    work() {
        const b = this.getB('李四');
        const c = b.getC('王五');
        c.work();
    }
}

class B {
    constructor(name) {
        this.name = name;
    }
    // B与C是好朋友,所以可以寻找C
    getC(name) {
        return new C(name);
    }
}

class C {
    constructor(name) {
        this.name = name;
    }
    // C可以做好这件事
    work() {
        console.log(this.name + '做好了这件事情');
    }
}

// 客户端
const a = new A('张三');
a.work(); // 王五做好了这件事情

可以看到虽然事情是完成了,但是A类里居然有C,但是A是不认识C的。所以这里的设计就不太合理。

实际上这是实际开发场景中常见的一种情况。对象A需要调用对象B的方法,对象B又需要调用对象C的方法。例如A.getXXX().getXXX().getXXX()类似这样的代码,如果你发现你的代码中也有这样的代码,那就该考虑一下是不是违反了迪米特法则,是否该重构一下了。

# 正面教材

将以上的代码重构一下,使其符合迪米特法则。代码如下:

class A {
    constructor(name) {
        this.name = name;
    }
    // A与B是好朋友,所以可以寻找B
    getB(name) {
        return new B(name);
    }
    // 一件难题,只有C可以解决
    work() {
        const b = this.getB('李四');
        b.work()
    }
}

class B {
    constructor(name) {
        this.name = name;
    }
    // B与C是好朋友,所以可以寻找C
    getC(name) {
        return new C(name);
    }
    work() {
        const c = this.getC('王五');
        c.work();
    }
}

class C {
    constructor(name) {
        this.name = name;
    }
    // C可以做好这件事
    work() {
        console.log(this.name + '做好了这件事情');
    }
}

// 客户端
const a = new A('张三');
a.work(); // 王五做好了这件事情

上面代码仅修改了A和B的work方法,使之符合了迪米特法则:

  • 类A只与最直接的朋友类B通信,不与类C通信
  • 类A只调用类B提供的方法即可,不用关心类B内部是如何实现的(至于B是怎么调用的C,A都不用关心)

相当于只能托自己的朋友办事,但是朋友是怎么帮忙的,我们并不需要知道。

# 总结

迪米特法则的目的是让类之间解耦,降低耦合度。只有这样,类的可复用性才会提高。

但是迪米特的弊端在于会产生大量的中转类或跳转类,导致系统的复杂度提升。

最近更新时间: 2020/11/18 11:08:57