天天看點

為什麼有人說面向對象程式設計就是面向接口程式設計?

"面向對象程式設計就是面向接口程式設計"

這句話相信, 很多人都在網上見過, 裝b利器.

我一開始也是這麼想的, 那些裝b者丢下這一句, 就沒下文了.

首先, 我認為這句話是1個假命題.

但是, 這句話是1個很好的建議, 也就是我們應該盡量地"面向接口程式設計".

一, 什麼是面向對象程式設計

這個問題, 相信很多人包括我也無法準确表達出答案.

我大概做個總結.

1. 首先, 你要用到面向對象的程式設計語言, 例如java, C# 等.

2. 其次, 用到面向對象的3大特性.  封裝, 繼承, 和多态. 其中最重要的是多态.

二, 什麼是面向接口程式設計.

我自己的了解:

在任何1個類(無論是抽象類或非抽象類,用戶端除外)中,  盡量不要出現非抽象類或者其對象.

當然完全不出現非抽象類是不可能的.

但是至少(建議你做到)

1. 類的某個成員(屬性)如果位于構造函數參數中,  或者這個成員有set()方法, 則這個成語不是1個非抽象類的對象(可以是接口或抽象類的對象)

2. 方法的參數不是1個非抽象類的對象.

也就是講, 類裡面盡量做到隻寫接口或者抽象類的名字, 而不是具體某個類的名字.

三, 為什麼要面向接口程式設計.

1. 實作多态.

2. 減少耦合性.

3. 令各個成員依賴與抽象, 而不是依賴與具體.

4. 友善維護和擴充.

上面的答案, 也是一搜一大堆.  令人一頭霧水.

其實上面4點, 根本的原因就是第4點. 友善維護和擴充.

也就是常常提到的封閉-開放原則.

四, 什麼是封閉-開放原則.

所謂封閉開放原則就是.

對修改封閉, 對擴充開放. (注意, 用戶端代碼修改是無可避免的, 指的是業務類的代碼修改封閉)

當你寫代碼寫到一半(或者已經release),   你的産品經理讓你增加點或者修改某些東西.

看起來隻需要修改一點點東西, 實際上如果類設計不好的話, 可能會牽一發動全身.

就是所謂的維護成本很大.

是不是連捅産品經理一刀的心都有了,  聽說最近深圳剛捅了1個..(悲劇默哀)

其實根本的解決方法就是一開始, 合理的設計類, 應用合理的設計模式.

盡量做到, 一旦有增加或者修改需求, 

我們都無需修改以前的類(對修改封閉)

而隻需增加1個新的類(通常是子類,   對擴充開放)

這個例子太極端?

更加極端的都有,   其實你用到大部分的類都是不能改的, 要麼你沒有修改權限, 要麼它們是用jar包釋出...

是以設計模式就十分重要了.

五, 類裡面出現具體類的缺點.

用1個很簡單很簡單的例子.

假如你的經理要你寫1個投資者類,  它可以買股票

你是這樣寫的(當然下面兩個類寫在兩個檔案内)

public class Invester{
    public void buyStock(Stock s,int amount){
        .....
        s.buy(amount);
        .....
    }
}


public class Stock(){
    public void buy(int amount){};

 }
           

好了, 過兩天, 經理要你加入買基金的功能.

除了添加Fund類外.

你還要在 Invester裡添加 buyFund()的方法.

如果過兩天經理再要你加入買期貨的功能.

再加入buyCommodity()方法.

實際上這樣, 你已經break了對修改封閉的原則了.

而Invester裡面的越來越臃腫, 太多類似功能的方法.

六, 改成面向接口

上面的根本錯誤就是Invseter的方法出現了非抽象類對象的參數 Stock s

我們應該把它改成1個接口.

例如我們添加1個可以投資的接口, 讓股票類Stock去實作這個接口

public class Invester{
    public void buyInvest(Investable i,int amount){
        .....
        i.buy(amount);
        .....
    }
}


public class Stock() implements Investable{
    @Override
    public void buy(int amount){};
}

public interface Investable{
    void buy(int amount);
}
           

如上面修改後的例子,

Invester裡出現的就是接口名字Investable.  就是所謂的面向接口程式設計了.

一旦經理叫你添加買基金方法.

隻需要添加Fund類, 讓它實作Investable接口.

而無需修改其他類的代碼.

通過這個例子我們再想深一層

加入這個程式不隻投資者這個角色, 例如還有投資經理(InvestmentMgr), 律師(Lawer).

它們很可能有類似的行為, 例如交稅(tax), 獲利(benefit) 等.

那麼最好都把交稅, 獲利等行為寫成接口, 讓它們去實作這些接口.

對這個程式的擴充性是有十分大的好處的.