2009年1月31日星期六

解耦合手段之四:Law of Demeter

迪米特法则(Law of Demeter),又称“最少知识原则”(Principle of Least Knowledge),也是主要针对面向对象思想的,可以简单的概括为“talk only to your immediate friends”。

具体来说,在面向对象的方法中,一个方法“M”和一个对象“O”只可以调用以下几种对象的方法:
1. O自己
2. M的参数
3. 在M中创建的对象
4. O的直接组件对象

Law of Demeter来源于1987年荷兰大学的一个叫做Demeter的项目。Craig Larman把Law of Demeter又称作“不要和陌生人说话”。在《程序员修炼之道》中讲LoD的那一章叫作“解耦合与迪米特法则”。可以看出迪米特法则是非常流行的解耦合手段之一。关于迪米特法则有一些很形象的比喻: 
如果你想让你的狗狗跑的话,你会对狗狗说还是对四条狗腿说? 
如果你去店里买东西,你会把钱交给店员,还是会把钱包交给店员让他自己拿? 

让店员自己从钱包里拿钱?这听起来有点荒唐,不过在我们的代码里这几乎是见怪不怪的事情了:
class Clerk {
    Store store;
    void SellGoodsTo(Client client)
    {
        money = client.GetWallet().GetMoney();//店员自己从钱包里拿钱了!
        store.ReceiveMoney(money);
    }
};

在《Clean Code》一书中,作者找到了Apache framework中的一段违反了LoD的代码:
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
这么长的一串对其它对象的细节,以及细节的细节,细节的细节的细节......的调用,违反了迪米特法则,增加了耦合,使得代码结构复杂、僵化,难以扩展和维护。

在《重构》一书中的各种“Bad smells of code”中有一种“smell”叫做“Feature Envy”(依恋情结),形象的描述了一种违反了LoC的情况。Feature Envy就是说一个对象对其它对象的内容更有兴趣,也就是说老是羡慕别的对象的成员、结构或者功能,大老远的调用人家的东西。这样的结构显然是不合理的。我们的程序应该写得比较“害羞”。不能像前面例子中的那个不把自己当外人的店员一样,拿过客人的钱包自己把钱拿出来。“害羞”的程序只和自己最近的朋友交谈。这种情况下应该调整程序的结构,让那个对象自己拥有它羡慕的feature,或者使用合理的设计模式(例如Facade和Mediator)。
店员的例子如果是这样就会好一点:
        money = client.GetMoney();//客户自己从钱包里拿钱
或者根本不用那么麻烦:
    void SellGoods(Money money)
    {
        store.ReceiveMoney(money);
    }

这一法则不仅仅局限于计算机领域,在其他领域也同样适用。据说美国人就在航天系统的设计中采用这一法则。

没有评论:

发表评论