ü 設計原則1:找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。
例如:對於一個鴨子類,不同的鴨子(真鴨子,木頭鴨子等)有不同的飛行行爲,呱呱叫行爲,所以要把這兩個行爲從鴨子類中分離出來,在鴨子類中只保存那些不變的部分。
ü 設計原則2:針對接口編程而不是針對實現編程。
這裏的接口有多個含義,它可以是java中的interface,也可以是抽象類。“針對接口編程”,關鍵就在多態。利用多態,程序可以針對超類型編程,執行時會根據實際狀況執行到真正的行爲,不會被綁死在超類型的行爲上。“針對超類型編程”這句話,可以更明確地說成“變量的聲明類型應該是超類型,通常是一個抽象類或者是一個接口,如此,只要是具體實現此超類型的類所產生的對象,都可以指定給這個變量。
舉個例子:
假設有一個抽象類Animal,其下有兩個實現類 Dog和Cat繼承自Animal。做法如下:
² 針對實現編程:
Dog dog = new Dog();
bj.bark();
注:聲明變量“dog” 爲Dog類型(是Animal的具體實現),會造成我們必須針對具體實現編碼。
² 針對接口/抽象類編程:
Animal animal = new Dog();
Animal.makeSound();
注:利用animal進行多態的調用。
設計原則3:多用組合(composition),少用繼承
使用組合建立系統具有很大的彈性,不僅可將行爲封裝成類,更可以“在運行時動態地改變行爲”,只要組合的行爲對象符合正確的接口標準即可。
例如:在設計原則一中我們把“飛行行爲”和“呱呱叫行爲”這兩個變化的行 爲從鴨子類中分離出來。這裏我們就設計這兩個行爲和鴨子類:
以上 以上爲兩個行爲接口和它的實現類。此時我們要做的就是把兩個行爲整合到鴨子類中,具體怎麼整合?繼承嗎?繼承只能繼承一個特定的類,因此用繼承將不能“在運行時動態地改變行爲”。那麼我們選用組合。
在Duck類中“加入兩個實例變量”,分別爲“flyBehavior”與“quackBehavior”,聲明爲接口類型(而不是具體類實現類型),每個鴨子對象都會動態地設置這些變量以在運行時引用正確的行爲類型(例如:FlyWithWings、Squeak等)。
此時我們就把兩個行爲組合到Duck類中了,既然使用了組合,我們怎麼在運行時動態地改變行爲呢?如下我們寫一個main函數來看看:
public static void mian(String args[]){
Duck duck = new Duck();
duck.setFlyBehavior(new FlyNoWay());
duck.setQuackBehavior(new Quack());
//此時若想要鴨子能飛,我們可以通過setter方法在運行時動態地改變行爲
duck.setFlyBehavior(new FlyWithWings());
}
Sping中依賴注入(IOC)使用的就是組合。