设计模式系列之设计原则(5)迪米特法则

定义

​ 只与直接朋友交谈,不和陌生人说话。其软件含义是:如果两个软件实体无需直接通信,那么就不应当发生直接调用关系,而是应该通过第三方转发调用。

​ 理解迪米特法则的关键在于定义中说明的两个词:朋友、说话。“说话”的含义是指类之间的调用行为,即所谓软件实体之间的通信。对于复杂的业务需求,可能产生比较长的通信链路。在通信的过程中,依照迪米特法则,要先判断对方是不是当前类的朋友,能够称得上朋友的软件实体包括以下:

  • 当前类对象本身(this)
  • 当前类的任何组件(成员变量)
  • 当前类的方法参数(输入参数、方法返回值)
  • 当前类方法创建或实例化的对象(new创建)

在方法内部,通过调用其他类的方法返回的对象不是当前类的朋友。

作用

从定义可知,迪米特法则限制了软件实体之间的通信深度,缩短了通信链路长度,强调了类的独立性。其优点如下

  • 降低类之间的耦合度,提高模块的独立性。
  • 独立性提高,则复用性、可维护性、可扩展性也提高。
  • 独立性提高,出现错误之后,影响范围缩小。

实现方法

​ 从命名可知,迪米特法则较其他原则具备更高的优先级。在设计类时,尽量较少类同其他外部的交流。设计或评价类是否符合迪米特法则的步骤主要两步:

  1. 当前类需要使用某一外部类时,判断外部类是否是当前类的朋友。
  2. 如果是朋友,则可以正常使用。
  3. 如果不是朋友,创建第三方类作为通信中介,连通当前类和外部类。

在运用迪米特法则是要注意以下5点:

  • 迪米特法则需要第三方类做通信中介,可能产生类爆炸问题,要权衡是否创建新的第三方类。

  • 尽量减少引用其他对象的次数。多一事不入少一事,引用越少,出现问题的风险越小。

  • 减低类成员的访问权限,使其他类不能调用类成员。

  • 设计类方法时,如果该方法不会增加类间关系,则对本类没有影响,则可以添加该方法。

  • 判断某类的设计是否符合迪米特法则时,可观察此类的import部分,如果导入的外部类不是当前类的朋友,则说明当前类不符合迪米特法则。

代码实践

业务场景: 老板问项目组长某位员工的名字。

以下是不符合迪米特法则的设计:

//老板类
//此时老板需要拿到员工类,让员工打印名字。
//但员工类不是老板类的朋友,因此这个老板类的设计不符合迪米特法则。
public class Boss {
    public void  getEmloye(TeamLeader teamLeader){
        //此处的employ是其他对象方法的返回值,不属于boss的朋友
        Employe employ = teamLeader.getEmploy();
        System.out.println(employ.getName());
    }
}

//项目组长类
public class TeamLeader {
    //返回一个员工对象
    public Employe getEmploy(){
        return new Employe("张三");
    }
}
//员工类
public class Employe {
    String name;
    Employe(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

观察以上代码,可对Boss类进行改造,将Employe类从Boss类中移除至第三方通信中介TeamLeader类中,新的类视图如下,

//老板类
public class Boss {
    public void  getEmloye(TeamLeader teamLeader){
        //同员工通信细节完全交给项目组长实现
        //老板类不直接同员工类通信
        teamLeader.getEmploy();
    }
}
//项目组长类
public class TeamLeader {
    public void getEmploy(){
        System.out.println(new Employe("张三").getName());
    }
}
//员工类
public class Employe {
    String name;
    Employe(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

对比以上两个版本的代码可以发现,出现不符合迪米特法则的类出现在较高层,即调用其他软件实体的高层类。并且,改造这些类一般是将不符合迪米特法则的代码块移动到第三方类中,代码块原有的功能不发生变化。

编程知识点

  • java语言通过位置(同包/跨包)、继承关系(子类/非子类)两个维度控制访问权限,可产生四种作用域组合关系,包括同包子类、同包非子类、跨包子类、跨包非子类,其中跨包非子类的“亲密关系”最薄弱。在确定访问权限时,一个维度确定两个组合。譬如同包权限,则指同包子类和同包非子类都可以访问。

    • private,私有权限。类内部可访问,子类不能访问,不能跨包访问。单一限制位置,只有类内部成员。
    • default,默认权限或包权限。同一个包内可以访问。单一限制位置,只有同包(同包子类/同包非子类)内部。
    • protected,保护访问权限。类内部可访问,同包(同包子类/同包非子类)可以访问,子类(同包子类/跨包子类)可以访问,跨包的非子类不能访问。组合限制,位置->同包(子类/非子类)可以访问,位置关系->同包子类可以访问.

    记忆点:只有最远的亲戚(跨包非子类)不能访问。

    • public,公共权限。任何位置、任何类可以访问。无限制。

特别地,private和protected不能修饰一般的外部类,否则编译就会报“modifier private not allowed here”,内部类另当别论。

  • 同一个项目下多个模块的src是连通的,直接查看src的类图会显示全部src下的类。规范做法是在src下创建自己的package,将类放在包中,此时查看包的类图即可看到包中所有类关系.

参考资料

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值