👉文章示例代码👈

迪米特法则也叫做最少知道原则。

定义

一个对象应该对其他对象保持最少的了解。

在《Head First 设计模式》一书中,针对该原则也强调:只和你的密友交流。

在程序中,出现在成员变量、方法的输入、输出参数中的类我们可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。

这些个成员朋友类的对象和当前对象之间存在关联、聚合或者组合关系,可以直接访问这些成员朋友类对象的方法。

场景示例

假设现在超市老板来超市向职工说要看看目前超市内的商品总数量。

这里会牵扯到几个实体类:老板类、职工类、商品类。

创建商品类

/**
 * @author zhh
 * @description 商品类
 * @date 2020-02-07 11:00
 */
public class Goods {
}

创建职工类

在职工类的内部实现一个职工查询商品数量的方法。

/**
 * @author zhh
 * @description 职工类
 * @date 2020-02-07 11:02
 */
public class Staff {

    /**
     * 职工查询商品数量
     * @param goods 商品列表
     */
    public void checkNumber(List<Goods> goods) {
        System.out.println("目前超市内商品总数为: " + goods.size());
    }
}

创建老板类

在老板类的内部实现老板要求职工查询商品数量的方法。

/**
 * @author zhh
 * @description 老板类
 * @date 2020-02-07 10:59
 */
public class Boss {

    /**
     * 老板要求职工查商品的数量
     * @param staff 职工
     */
    public void requireCheckNumber(Staff staff) {
        List<Goods> goodsList = new ArrayList<Goods>();

        // 这里模拟从数据库查商品数量
        for (int i = 0; i < 50; i++) {
            goodsList.add(new Goods());
        }

        staff.checkNumber(goodsList);
    }
}

测试类及输出

/**
 * @author zhh
 * @description 测试类
 * @date 2020-02-07 11:09
 */
public class Test {

    public static void main(String[] args) {
        Boss boss = new Boss();
        Staff staff = new Staff();

        boss.requireCheckNumber(staff);
    }
}

测试类的输出结果如下:

目前超市内商品总数为: 50

类结构图

以上示例类的结构图如下所示

问题所在

前面提到过,迪米特法则强调只和密友交流。

Boss 类当中, Staff 作为方法的入参可以作为直接的朋友类。而 Goods 是出现在方法体内部的类,并不属于朋友类。

Boss 直接要求 Staff 查询商品的总数量,只需要将结果告知即可。 Boss 并不需要关注 Goods 这个类。

方案调整

调整老板类

public class Boss {

    /**
     * 老板要求职工查商品的数量
     * @param staff 职工
     */
    public void requireCheckNumber(Staff staff) {
        staff.checkNumber();
    }
}

调整职工类

public class Staff {

    /**
     * 职工查询商品数量
     */
    public void checkNumber() {
        List<Goods> goodsList = new ArrayList<Goods>();

        // 这里模拟从数据库查商品数量
        for (int i = 0; i < 50; i++) {
            goodsList.add(new Goods());
        }
        System.out.println("目前超市内商品总数为: " + goodsList.size());
    }
}

类结构图

调整后的整体类结构图如下

通过前后对比类图,我们不难发现,调整后的类结构中 Boss 类和 Goods 类没有直接的关联关系。

优点

  • 降低类之间的耦合,提高模块的相对独立性。
  • 提高类的可复用性和系统的扩展性。

缺点

过度使用迪米特法则会使系统产生大量中介类,从而增加系统的复杂性,使模块之间的通信效率降低。

总结

迪米特法则主要强调以下两点:

  • 从依赖者的角度来说,只依赖应该依赖的对象。
  • 从被依赖者的角度说,只暴露应该暴露的方法。

注意点

  • 在类的划分上,应创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。
  • 在类的结构设计上,尽量降低类成员的访问权限。
  • 在类的设计上,优先考虑将一个类设置成不变类。
  • 在对其他类的引用上,将引用其他对象的次数降到最低。
  • 不暴露类的属性成员,而应该提供相应的 get 和 set 方法。
  • 谨慎使用序列化 (Serializable) 功能。

参考

  • 《Head First 设计模式》
  • 《大话设计模式》