不使用工廠模式
我們現在有一個汽車方法,實現如下:
public interface Car {
void run();
}
public class Audi implements Car {
@Override
public void run() {
System.out.println("奧迪在跑");
}
}
public class Byd implements Car {
@Override
public void run() {
System.out.println("比亞迪在跑");
}
}
public class Client01 {
public static void main(String[] args) {
Car c1 = new Audi();
Car c2 = new Byd();
c1.run();
c2.run();
}
}
類圖如下:
可以看到,在使用過程中,調用者既要依賴接口,也要依賴具體類和方法。
工廠模式的核心思想
實現創建者和調用者的分離:實例化對象的時候用工廠方法代替new操作。將選擇實現類、創建對象統一管理和控制,從而將調用者跟我們的實現解耦。
簡單工廠模式
引入工廠模式的思想,上面的代碼可以優化一下,將實例化具體類的代碼封裝起來,新建一個CarFactory,具體實現如下:
public class CarFactory {
public static Car createCar(String type){
if ("奧迪".equals(type)){
return new Audi();
} else if ("比亞迪".equals(type)){
return new Byd();
} else {
return null;
}
}
}
public class Client02 {
public static void main(String[] args) {
Car c1 = CarFactory.createCar("奧迪");
Car c2 = CarFactory.createCar("比亞迪");
c1.run();
c2.run();
}
}
類圖如下:
這樣我們的調用者只需要與CarFactory和Car發生依賴關係。體現了工廠模式的思想,實現了創建者和調用者的分離。
我們稱這種處理方法爲簡單工廠模式或者靜態工廠模式,就是工廠類一般是用靜態方法,通過接收的參數的不同來返回不同的對象實例。值得一提的是,簡單工廠模式不是一種設計模式,更像是一種編程習慣。
簡單工廠模式還有另外一種寫法:
public class CarFactory2 {
public static Car createAudi(){
return new Audi();
}
public static Car createByd(){
return new Byd();
}
}
雖然簡單工廠模式優化了我們最初的代碼,但是還是存在一定的問題。如果增加新產品,不修改代碼的話是實現不了的。針對這一問題,我們需要用到工廠方法模式。
工廠方法模式
工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。
需要注意的是,工廠方法讓子類決定要實例化的類是哪一個,“決定”並不是指模式允許子類本身在運行時做決定,而是指在編寫創建者類時,不需要知道實際創建的產品是哪一個。選擇了使用哪個子類,自然就決定了實際創建的產品是什麼。
工廠方法模式提供了一組實現了相同接口的工廠類,代碼實現如下(Car、Audi和Byd的代碼和上面簡單工廠模式的代碼相同):
public interface CarFactory {
Car createCar();
}
public class AudiFactory implements CarFactory {
@Override
public Car createCar() {
return new Audi();
}
}
public class BydFactory implements CarFactory {
@Override
public Car createCar() {
return new Byd();
}
}
public class Client {
public static void main(String[] args) {
Car c1 = new AudiFactory().createCar();
Car c2 = new BydFactory().createCar();
c1.run();
c2.run();
}
}
類圖如下:
調用者在實例化對象時,只需要依賴接口,而不是具體類。
工廠方法模式和簡單工廠模式最大的不同在於,簡單工廠模式只有一個(對於一個項目或者一個獨立模塊而言)工廠類,而工廠方法模式有一組實現了相同接口的工廠類。
開閉原則(OCP):一個軟件的實體應該對擴展開放,對修改關閉。
簡單工廠模式和工廠方法模式比較
結構複雜度:從結構複雜度來看,很顯然簡單工廠模式佔優勢。簡單工廠模式只需要一個工廠類,而工廠方法模式的工廠類隨着產品類個數增加而增加,這無疑會使類的個數越來越多,從而增加了結構的複雜程度。
代碼複雜度:代碼複雜度和結構複雜度是一堆矛盾,既然簡單工廠模式在結構方面相對簡潔,那麼它在代碼方面肯定比工廠方法模式複雜。簡單工廠模式的工廠類隨着產品類的增加需要增加很多方法(或代碼),而工廠方法模式每個具體工廠類只完成單一任務,代碼簡潔。
客戶端編程難度:工廠方法模式雖然在工廠類的結構中引入了接口從而滿足了OCP,但是在客戶端編碼中需要對工廠類進行實例化。而簡單工廠模式的工廠類是個靜態類,在客戶端無需實例化,這無疑是一個吸引人的優點。
管理上的難度:(1)擴展度:工廠方法模式完全滿足OCP,即它有非常好的擴展性。但是簡單工廠模式也具有良好的擴展性——擴展的時候僅需修改少量代碼(修改工廠類的代碼)就可以滿足擴展性的需求了。儘管這沒有完全滿足OCP,但我們不需要太拘泥於設計理論,即使是sun提供的Java官方工具中也有相當多沒有滿足OCP的例子。(2)維護性:假如某個具體產品類需要進行一定的修改,很可能需要修改對應的工廠類。當同時需要修改多個產品類的時候,工廠類的修改會變得相當麻煩(對號入座已經是一個問題了)。反而簡單工廠模式沒有這些麻煩,當多個產品類需要修改時,簡單工廠模式仍然僅需要修改唯一的工廠類(無論怎樣都能修改到滿足要求,大不了把這個類重寫)。
根據設計理論建議:工廠方法模式。但實際上,我們一般都用簡單工廠模式。
以上爲工廠方法模式的學習筆記,此文章爲尚學堂視頻的學習筆記+自己總結。參考資料:Head First 設計模式。