当前位置 博文首页 > 蔡小明:Java设计模式(3:接口隔离原则和迪米特法则详解)

    蔡小明:Java设计模式(3:接口隔离原则和迪米特法则详解)

    作者:蔡小明 时间:2021-06-09 18:28

    接口隔离原则:使用多个接口,而不使用单一的接口,客户端不应该依赖它不需要的接口。尽量的细化接口的职责,降低类的耦合度。 迪米特法则:又被成为 最少知道原则,指的是一个对象应该对其他对象保持最少的了解。一个实体类应当尽量少地和其他实体之间发生相互作用,使得系统模块相互独立。形象来说就是:只和朋友交流,不和陌生人说话。

    一、接口隔离原则

    使用多个接口,而不使用单一的接口,客户端不应该依赖它不需要的接口。尽量的细化接口的职责,降低类的耦合度

    我们先来看一个例子:

    小明家附近新开了一家动物园,里面有老虎、鸟儿、长颈鹿.....周末在逛动物园的时候,小明突发奇想,想用一种方式记录一下这些动物的习性,于是他将老虎和鸟儿的习性结合了一下,写了下面这段代码:

    动物行为

    // 动物行为
    public interface Animal {
    
        // 吃
        public void eat();
    
        // 游泳
        public void swim();
    
        // 飞
        public void fly();
    }
    

    老虎Tiger

    // 老虎
    public class Tiger implements Animal {
        @Override
        public void eat() {
            System.out.println("老虎在吃鸡肉.....");
        }
    
        @Override
        public void swim() {
            System.out.println("老虎在游泳.....");
        }
    
        @Override
        public void fly() {
            System.out.println("老虎不能飞.....");
        }
    }
    

    小鸟Brid

    // 小鸟
    public class Brid implements Animal {
        @Override
        public void eat() {
            System.out.println("小鸟在吃虫子.....");
        }
    
        @Override
        public void swim() {
            System.out.println("小鸟不会游泳.....");
        }
    
        @Override
        public void fly() {
            System.out.println("小鸟正在飞.....");
        }
    }
    

    写完上面的三段代码后,小明发现了问题:在Animal接口的三个方法中,Tiger是不会飞的,所以fly()方法对于Tiger是没有用的;Bird是不会游泳的,所以swim()方法对于Bird是没有用的。这样一来,Brid类和Tiger类都会空置一个方法,对于代码的结构设计来说不太合理。于是,他划掉了上面的三段代码,仔细思索了一会儿,写出了下面这几段代码:

    // 游泳
    public interface ISwim {
        public void swim();
    }
    
    // 吃
    public interface IEat {
        public void eat();
    }
    
    // 飞
    public interface IFly {
        public void fly();
    }
    

    小鸟Bird

    // 小鸟
    public class Brid implements IEat,IFly {
        @Override
        public void eat() {
            System.out.println("小鸟在吃虫子.....");
        }
    
        @Override
        public void fly() {
            System.out.println("小鸟正在飞.....");
        }
    }
    

    老虎Tiger

    // 老虎
    public class Tiger implements IEat,ISwim {
        @Override
        public void eat() {
            System.out.println("老虎在吃鸡肉.....");
        }
    
        @Override
        public void swim() {
            System.out.println("老虎在游泳.....");
        }
    }
    

    这样来看,将eatswimfly三种方法拆分开来,分别放在三个不同的接口里,这样动物拥有哪几种习性就实现哪几个接口,不会再用空置的方法存在,这样看起来也简洁明了,来看看类图:

    二、迪米特法则

    又被成为最少知道原则,指的是一个对象应该对其他对象保持最少的了解。一个实体类应当尽量少地和其他实体之间发生相互作用,使得系统模块相互独立。形象来说就是:只和朋友交流,不和陌生人说话

    迪米特法则认为,一个对象或方法,它只能够调用以下对象:

    • 该对象本身
    • 作为参数传进来的对象
    • 在方法内创建的对象

    我们先来模拟一个超市购物的场景:顾客Customer到收银台结账,收银员PaperBoy负责收钱。

    顾客的钱包Wallet

    // 钱包
    public class Wallet {
    
        // 钱包里装的钱
        private Float value;
    
        // 构造器
        public Wallet(Float value) {
            this.value = value;
        }
    
        // 获得钱包里的钱的金额
        public Float getMoney(){
            return this.value;
        }
    
        // 付账时 减钱
        public void reduceMoney(Float money){
            this.value -= money;
        }
    }
    

    顾客Customer

    // 顾客
    public class Customer {
    
        private Wallet wallet = new Wallet(50f);
    
        public Wallet getWallet() {
            return wallet;
        }
    }
    

    收银员PaperBoy

    // 收银员
    public class PaperBoy {
    
        // 收银员收钱
        public void charge(Customer customer,Float money){
            Wallet wallet = customer.getWallet();
            if (wallet.getMoney() >= money){
                System.out.println("顾客付账:" + money +"元");
                // 减去 应付的钱
                wallet.reduceMoney(money);
                System.out.println("钱包里还剩:"+wallet.getMoney()+"元");
            } else {
                System.out.println("钱包里的金额不够......");
            }
        }
     }
    

    测试、运行

    // 测试
    public static void main(String[] args) {
        PaperBoy paperBoy = new PaperBoy();
        Customer customer = new Customer();
        paperBoy.charge(customer,20f);
    }
    


    从测试代码和运行的结果来看,好像并没有什么问题。让我们来看一下类图:

    从类图中我们发现:PaperBoy类与Wallet类有着千丝万缕的关系,顾客(Customer)的钱包(Wallet)好像并不是自己来控制的,而是由收银员(PaperBoy)来决定的,就连钱包(Wallet)里面的钱够不够也是由收银员(PaperBoy)来判断的;相当于顾客(Customer)将自己的钱包(Wallet)暴露给了收银(PaperBoy),这样来看,问题就很严重了,顾客(Customer)的隐私受到了侵犯,说大点就是民事纠纷,是可以上法庭的,可以通过法律追究责任的。所以我们思考良久,将上述代码改成下面这般:

    钱包Wallet类不变顾客Customer去掉给出钱包的getWallet()方法,增加付钱的pay()方法

    // 顾客
    public class Customer {
    
        private Wallet wallet = new Wallet(50f);
    
        // 顾客自己付钱
        public void pay(Float money){
            if (wallet.getMoney() >= money){
                System.out.println("顾客付账:" + money +"元");
                // 减去 应付的钱
                wallet.reduceMoney(money);
                System.out.println("钱包里还剩:"+wallet.getMoney()+"元");
            } else {
                System.out.println("钱包里的金额不够......");
            }
        }
    }
    

    收银员PaperBoy类中的charge()方法中的代码删除原有的逻辑,改为调用顾客Customer类中的付钱pay()方法

    // 收银员
    public class PaperBoy {
    
        // 收银员收钱
        public void charge(Customer customer,Float money){
            customer.pay(money);
        }
    }
    

    测试代码不变,我们再来看看类图:

    从类的结构图来看:收银员PaperBoy只和顾客Customer有联系,钱包Wallet只和顾客Customer有联系。再此情况下,如果把钱包Wallet也当作一个人来看的话,这个就是如下的关系:

    • 顾客Customer和钱包Wallet是朋友
    • 顾客Customer和收银员PaperBoy是朋友
    • 钱包Wallet和收银员PaperBoy是陌生人

    这个就符合我们所说的迪米特法则中的核心:只和朋友交流,不和陌生人说话

    bk
    下一篇:没有了