设计模式学习之——六大设计原则之五:迪米特法则

迪米特法则又称最少知识原则(Least Knowledge Principle, LKP)
解释1:一个对象应对其他对象有最少的了解
解释2:Only talk to your immedate friends(只与直接的朋友通信)
对类的低耦合提出明确要求:(4点)
1.只和朋友交流
eg:
    老师教班长去清点班中女生人数(在老师类中初始化女生)

老师类:
public class Teacher
{
    //老师对班长发布命令,清点女生
    public void commond(GroupLeader groupLeader)
    {
        List<Girl> listGirls = new ArrayList();
        //初始化女生
        for (int i = 0; i < 20; i++)
        {
            listGirls.Add(new Girl());
            //告诉班长开始执行清点任务
            groupLeader.countGirls(listGirls);
        }
    }
}
班长类:
public class GroupLeader
{
    //清点女生数量
    public void countGirls(List<Girl> listGirls)
    {
        //输出女生数量:listGirls.size()
    }
}
女生类:
public class Girl
{
}
场景类:
public class Client
{
    public static void main(String[] args)
    {
        Teacher teacher = new Teacher();
        //老师发布命令
        teacher.commond(new GroupLeader());
    }
}
运行结果是:20

考虑程序中存在的问题:
    先考虑Teacher类有几个朋友类?它仅有一个朋友类GroupLeader,为什么Girl不是朋友类呢?
    朋友类的定义:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
    现在我们看,Girl类就是出现在commond方法体内的,所以说 不属于Teacher类的朋友类。

所以,我们需要修改类关系图:


修改后的老师类:
public class Teacher
{
    //老师对班长发布命令,清点女生
    public void commond(GroupLeader groupLeader)
    {
        //告诉班长开始执行清点任务
        groupLeader.countGirls();
    }
}
修改后的班长类:
public class GroupLeader
{
    private List<Girl> listGirls;
    public GroupLeader(List<Girl> _listGirls)
    {
        this.listGirls = _listGirls;
    }
    //清点女生数量
    public void countGirls(List<Girl> listGirls)
    {
        //输出女生数量:this.listGirls.size()
    }
}
修改后的场景类:
public class Client
{
    public static void main(String[] args)
    {
        //产生一个女生群体
        List<Girl> listGirls = new ArrayList<Girl>();
        //初始化女生
        for (int i = 0; i < 20; i++)
        {
            listGirls.Add(new Girl());
        }
        Teacher teacher = new Teacher();
        //老师发布命令
        teacher.commond(new GroupLeader(listGirls));
    }
}

简单修改程序,将Teacher中对女生的初始化放到了场景类中,同时在GroupLeader中增加了对Girl的注入,避开了Teacher类对陌生类Girl的访问,降低了系统间的耦合,提高了系统的健壮性。
注意:一个类只和朋友交流,不与陌生类交流,不要出现 getA().getB().getC().getD() 这种情况(除非每个点号后面的返回类型都相同),类与类间的关系是建立在类间的,而不是方法间的

2. 朋友间也是有距离的
eg:
安装软件时,会有导向动作,第一步做什么,第二步做什么等等,即是顺序执行。具体到程序中就是:调用一个或多个类,先执行第一个方法,然后第二个方法根据返回结果再来看是否可以调用第三个方法。
类关系图:

导向类:
public class Wizard
{
    private Random rand = new Random(System.currentTimeMillis());
    public int first()
    {
        //执行第一个方法
        return rand.nextInt(100);
    }
 
    public int second()
    {
        //执行第二个方法
        return rand.nextInt(100);
    }
 
    public int third()
    {
        //执行第三个方法
        return rand.nextInt(100);
    }
}
InstallSoftware类:
public class InstallSoftware
{
    public void installWizard(Wizard wizard)
    {
        int first = wizard.first();
        if (first > 50)
        {
            int second = wizard.second();
            if (second > 50)
            {
                int third = wizard.third();
                if (third > 50)
                    wizard.first();
            }
        }
    }
}
场景类:
public class Client
{
    public static void main(String[] args)
    {
        InstallSoftware invoker = new InstallSoftware();
        invoker.installWizard(new Wizard());
    }
}

    现在,我们可以来看下程序中存在什么问题?Wizard把太多的方法暴露给InstallSoftware类,两者朋友类关系太亲密了,耦合关系变得异常牢固。
    此时如果我们要将Wizard类中的first方法返回值的类型由int修改为boolean的话,就需要修改InstallSoftware类,从而把修改变更的风险扩散了。
    因此这样的耦合是季度不合适的,重新设计吧!!重构后如下图:


    在Wizard类中增加一个installWizard方法,对安装过程进行封装,同时,把原有的三个public方法改成private方法
修改后的导向类如下:
public class Wizard
{
    private Random rand = new Random(System.currentTimeMillis());
    private int first()
    {
        //执行第一个方法
        return rand.nextInt(100);
    }
    private int second()
    {
        //执行第二个方法
        return rand.nextInt(100);
    }
    private int third()
    {
        //执行第三个方法
        return rand.nextInt(100);
    }
    //软件安装过程
    public void installWizard()
    {
        int first = wizard.first();
        if (first > 50)
        {
            int second = wizard.second();
            if (second > 50)
            {
                int third = wizard.third();
                if (third > 50)
                    wizard.first();
            }
        }
    }
} 
这样Wizard类就只对外公布了一个public方法,即便修改first方法的返回值,影响的也仅仅只是Wizard本身,其他类不受影响,这就显示了类的高内聚性。
少量修改InstallSoftware类
public class InstallSoftware
{
    public void installWizard(Wizard wizard)
    {
        //直接调用
        wizard.installWizard();
    }
}
注意:迪米特法则要求类“羞涩”一点,尽量不要对外公布太多public犯法和非静态的public变量,尽量内敛,多使用private,package-private、protected等访问权限。

3. 自己的就是自己的
原则:如果一个方法放在本类中,即不增加类间关系,也对本类不产生负面影响,就放置在本类中。
4. 谨慎使用Serializable
    这个是项目管理的问题咯。小码农不考虑,略~





欢迎转载,转载注明出处,谢谢
Mr.傅:阅读自《设计模式之禅》




没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试