"面向對象程式設計就是面向接口程式設計"
這句話相信, 很多人都在網上見過, 裝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) 等.
那麼最好都把交稅, 獲利等行為寫成接口, 讓它們去實作這些接口.
對這個程式的擴充性是有十分大的好處的.