Java設計模式(3:接口隔離原則和迪米特法則詳解)


一、接口隔離原則

使用多個接口,而不使用單一的接口,客戶端不應該依賴它不需要的接口。盡量的細化接口的職責,降低類的耦合度

我們先來看一個例子:

小明家附近新開了一家動物園,里面有老虎、鳥兒、長頸鹿.....周末在逛動物園的時候,小明突發奇想,想用一種方式記錄一下這些動物的習性,於是他將老虎和鳥兒的習性結合了一下,寫了下面這段代碼:

動物行為

// 動物行為
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是陌生人

這個就符合我們所說的迪米特法則中的核心:只和朋友交流,不和陌生人說話


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM