六大设计原则:迪米特法则

1,414 阅读5分钟

不知不觉,这已经是六大设计原则的最后一遍了,写完这篇也算是完成了了这个序列了。当然除了学习设计原则,我们还有很多设计模式是可以去了解的和学习的。迪米特法则是我觉得最有意思的设计原则,来看下吧。

定义

迪米特法则:又叫作最少知识原则,一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。英文简写为: LOD。

这个是产生于 1987 年美国东北大学的一个名为迪米特(Demeter)的研究项目,由伊恩·荷兰(Ian Holland)提出,被 UML 创始者之一的布奇(Booch)普及,后来又因为在经典著作《程序员修炼之道》(The Pragmatic Programmer)提及而广为人知。

通俗的说就是如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。

重点

迪米特法则目的是降低类之间的耦合度,提高模块的相对独立性。

其中,我印象最深的一句话是:只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)。

它的意思就是说每个对象都会和其它对象有耦合关系,有关系的就叫做朋友,例如当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些就是朋友,而对象的朋友的朋友和对象的关系就是”陌生人“。

迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。

那我们应该怎么去做呢

  1. 在类的结构设计上,尽量降低类成员的访问权限。

  2. 在对其他类的引用上,将引用其他对象的次数降到最低。

  3. 对象于对象之间需要有直接联系才关联。

  4. 不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。

优点

  1. 降低了类之间的耦合度,提高了模块的相对独立性。

  2. 由于亲合度降低,从而提高了类的可复用率和系统的扩展性。

举例

我们就举例子我们生活上到处可见买二手房情况。

定义买家为Buyer类,卖家为Seller类,中介为AgentComputer类。

Seller类有销售房子的方法sellHouse。

/// 卖方
class Seller {
    func sellHouse() {
        print("看下房子信息吧")
    }
}

中介类AgentComputer有获取房源的方法getHouseInfo。

/// 中介
class AgentComputer {
    func getHouseInfo(seller: Seller) {
        seller.sellHouse()
    }
}

买方通过中介去找房源信息wantToBuyHouse。

/// 买方
class Buyer {
    func wantToBuyHouse() {
        let a = AgentComputer()
        let s = Seller()
        a.getHouseInfo(seller: s)
    }
}

输出代码:

var buyer = Buyer()
buyer.wantToBuyHouse()

打印结果:

看下房子信息吧

这么一看,的确卖方是拿到房子的信息。但是,上面写的代码缺违背了迪米特法则,在买方那里居然能有卖方的对象,如果真的知道卖方的对象,那我们何必就去找中介呢,对吧。所以中介是肯定不会把卖方的信息暴露给买方的。也可以认为买方和卖方式没有直接关系的。

我们改一下代码,中介类的getHouseInfo方法,就不对外暴露卖方了。

/// 中介
class AgentComputer {
    func getHouseInfo() {
        let seller = Seller()
        seller.sellHouse()
    }
}

接着买方的请求也跟着变化了

/// 买方
class Buyer {
    func wantToBuyHouse() {
        let a = AgentComputer()
        a.getHouseInfo()
    }
}

这样一改,打印的结果依然没有问题。那这样的做法好处是什么呢

买方类是不是就只有和中介是朋友,中介是买方和卖方的方法,卖方也只有中介的朋友,那这样子,耦合度是不是比之前降低了。要是有一天,卖方类发生了变化,买方类也不会有影响对吧。

总结

从这个例子,我们是不是可以想到为什么我们很经常要对第三方库进行二次封装了呢?除了可以扩展第三方库功能外,还有一点就是工程不会直接对第三方就行直接关系。

例如我们OC使用提示框,我们就用第三方库MBProgressHUD,某一天,我们不想用这个了,想用SVProgressHUD了。如果项目没有对这二次封装,那一处处改是不是很麻烦,因为耦合度太大了,如果我们有二次封装的类,是不是直接在那里进行更改就行。

6大设计原则总结起来就是:降低对象之间的耦合,增加程序的可复用性、可扩展性和可维护性。

题外话

到这里,六大设计原则总算写完了,这一是我第一次写系列性文章,总体上来看差强人意吧。里面的写的例子都是比较简单,更希望做到就是不用看Demo也能明白写什么。

按国际惯例,附上Github示例代码

如果以上说法有不足之处,欢迎留意。