工廠模式
其主要目的是封裝對象的創建過程,使客戶端代碼和具體的對象實現解耦。這樣子就不用每次都new對象,更換對象的話,所有new對象的地方也要修改,違背了開閉原則(對擴展開放,對修改關閉)。使用工廠來生產對象,更換對象也直接在工廠更換即可。
工廠模式的主要好處包括:
- 解耦合:工廠模式將對象的創建過程與客戶端代碼分離,客戶端不需要知道具體的對象是如何創建的,只需要通過工廠方法獲取對象即可,從而降低了代碼之間的耦合度。
- 靈活性:由于工廠負責創建對象,客戶端可以通過工廠方法獲取不同的對象實例,而無需關心具體的實現細節,從而提高了系統的靈活性。
- 可擴展性:如果需要添加新的產品類型,只需在工廠中添加相應的產品創建邏輯,而不需要修改客戶端代碼,這樣可以很方便地擴展系統的功能。
- 統一管理:工廠模式將對象的創建集中在一個地方,便于統一管理和維護,提高了代碼的可維護性。
使用場景:
- 當一個系統需要創建多個類型的對象,并且這些對象之間存在著共同的接口時,可以考慮使用工廠模式。
- 當客戶端不需要知道具體的對象是如何創建的,只需要獲取對象實例時,可以使用工廠模式。
- 當系統需要動態地決定創建哪種類型的對象時,可以使用工廠模式。
工廠模式包含以下幾個核心角色:
- 抽象產品(Abstract Product):**定義了產品的共同接口或抽象類。**它可以是具體產品類的父類或接口,規定了產品對象的共同方法。
- 具體產品(Concrete Product):實現了抽象產品接口,定義了具體產品的特定行為和屬性。
- 抽象工廠(Abstract Factory):聲明了創建產品的抽象方法,可以是接口或抽象類。它可以有多個方法用于創建不同類型的產品。
- 具體工廠(Concrete Factory):實現了抽象工廠接口,負責實際創建具體產品的對象。
這里介紹三種工廠:
- 簡單工廠模式(不屬于GOF的23種經典設計模式)
- 工廠方法模式
- 抽象工廠模式
簡單工廠模式
簡單工廠不是一種設計模式,反而比較像是一種編程習慣。
結構:
簡單工廠包含如下角色:
- 抽象產品 :定義了產品的規范,描述了產品的主要特性和功能。
- 具體產品 :實現或者繼承抽象產品的子類
- 具體工廠 :提供了創建產品的方法,調用者通過該方法來獲取產品。
使用場景:
- 當對象的創建邏輯相對簡單,并且不需要頻繁地進行變更時,可以考慮使用簡單工廠模式。
- 在客戶端只知道所需產品的名稱或類型,而不需要關心產品的創建過程時,可以使用簡單工廠模式。
實現思路:
// 抽象產品接口
interface Product { void show();
}// 具體產品類A
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("This is product A.");}
}// 具體產品類B
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("This is product B.");}
}// 簡單工廠類
class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();}return null;}
}// 客戶端
public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.show();Product productB = SimpleFactory.createProduct("B");productB.show();}
}
上面的工廠類創建對象的功能定義為靜態的,這個屬于是靜態工廠模式,當然你也可以不設置為靜態的。
優缺點:
優點:
- 簡單工廠模式中,客戶端通過工廠類的靜態方法來獲取產品實例,而不需要直接實例化具體產品類。如果要實現新產品直接修改工廠類,而不需要在原代碼中修改。
缺點:
- 工廠類負責創建所有產品,因此如果系統需要添加新的產品類型,需要修改工廠類,違反了開放封閉原則。
工廠方法模式
使用工廠方法模式可以完美的解決簡單工廠模式的缺點,完全遵循開閉原則。
概念
定義一個用于創建對象的接口,讓子類決定實例化哪個產品類對象。工廠方法使一個產品類的實例化延遲到其工廠的子類。
結構
工廠方法模式的主要角色:
- 抽象工廠(Abstract Factory):提供了創建產品的接口,調用者通過它訪問具體工廠的工廠方法來創建產品。
- 具體工廠(ConcreteFactory):主要是實現抽象工廠中的抽象方法,完成具體產品的創建。
- 抽象產品(Product):定義了產品的規范,描述了產品的主要特性和功能。
- 具體產品(ConcreteProduct):實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間一一對應。
圖例
使用工廠方法模式對上例進行改進:
工廠方法模式適用于需要創建一系列相關對象的情況
// 抽象產品接口
interface Product {void show();
}// 具體產品類A
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("This is product A.");}
}// 具體產品類B
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("This is product B.");}
}// 抽象工廠類
interface Factory {Product createProduct();
}// 具體工廠類A,負責創建產品A
class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 具體工廠類B,負責創建產品B
class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}// 客戶端
public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.show();Factory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.show();}
}
于是乎要增加產品類時只要相應地增加工廠類,不需要修改工廠類的代碼了,這樣就解決了簡單工廠模式的缺點。
使用場景:
- 當需要創建的對象是一個具體的產品,但是不確定具體產品的類型時,可以使用工廠方法模式。
- 在工廠類中定義一個創建產品的抽象方法,由子類負責實現具體產品的創建過程,從而實現了產品的創建和客戶端的解耦。
優缺點:
優點:
- 工廠方法模式中,客戶端通過調用工廠類的方法來創建產品,具體產品的創建邏輯由子類實現,不同的產品由不同的工廠子類負責創建。
- 工廠方法模式符合開放封閉原則,因為客戶端可以通過新增工廠子類來添加新的產品類型,而無需修改原有的代碼。
缺點:
- 每增加一個產品就要增加一個具體產品類和一個對應的具體工廠類,這增加了系統的復雜度。
抽象工廠模式
抽象工廠模式通常涉及一族相關的產品,每個具體工廠類負責創建該族中的具體產品。
使用場景:
- 當一個系統需要創建一系列相互關聯或相互依賴的產品對象時,可以考慮使用抽象工廠模式。
- 抽象工廠模式提供了一個創建一組相關或相互依賴對象的接口,客戶端可以通過該接口來創建產品族中的不同產品,而不需要關心具體的產品實現。
所以由此也可看出,普通工廠模式,工廠方法模式都只是單一產品類的工廠;而很多時候我們需要綜合性的,需要生產多等級產品的工廠。下圖所示橫軸是產品等級,也就是同一類產品;縱軸是產品族,也就是同一品牌的產品,同一品牌的產品產自同一個工廠:
結構
抽象工廠模式的主要角色如下:
- 抽象工廠(Abstract Factory):提供了創建產品的接口,它包含多個創建產品的方法,可以創建多個不同等級的產品。
- 具體工廠(Concrete Factory):主要是實現抽象工廠中的多個抽象方法,完成具體產品的創建。
- 抽象產品(Product):定義了產品的規范,描述了產品的主要特性和功能,抽象工廠模式有多個抽象產品。
- 具體產品(ConcreteProduct):實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間是多對一的關系。
代碼案例:
// 抽象產品接口
interface Product {void show();
}// 具體產品類A
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("This is product A.");}
}// 具體產品類B
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("This is product B.");}
}// 抽象工廠接口
interface AbstractFactory {Product createProductA();Product createProductB();
}// 具體工廠類,負責創建產品A和產品B
class ConcreteFactory implements AbstractFactory {@Overridepublic Product createProductA() {return new ConcreteProductA();}@Overridepublic Product createProductB() {return new ConcreteProductB();}
}// 客戶端
public class Client {public static void main(String[] args) {AbstractFactory factory = new ConcreteFactory();Product productA = factory.createProductA();productA.show();Product productB = factory.createProductB();productB.show();}
}
-
使用場景:
- 當需要創建的對象是一系列相互關聯或相互依賴的產品族時,如電器工廠中的電視機、洗衣機、空調等。
- 系統中有多個產品族,但每次只使用其中的某一族產品。如有人只喜歡穿某一個品牌的衣服和鞋。
- 系統中提供了產品的類庫,且所有產品的接口相同,客戶端不依賴產品實例的創建細節和內部結構。
優缺點
優點:
當一個產品族中的多個對象被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的對象。
缺點:
當產品族中需要增加一個新的產品時,所有的工廠類都需要進行修改。
模式擴展 (利用反射機制來創建對象)
簡單工廠+配置文件解除耦合
可以通過工廠模式+配置文件的方式解除工廠對象和產品對象的耦合。
通過使用配置文件,將創建對象的參數存儲在外部配置文件中,可以在不修改客戶端代碼的情況下,通過修改配置文件來改變對象的創建方式。這樣就可以實現對創建邏輯的解耦合,客戶端不需要知道具體的創建方式,只需要從工廠類獲取對象即可。
具體實現步驟如下:
- 在配置文件中配置需要創建的對象的類名或者類型。
- 在簡單工廠類中讀取配置文件,并根據配置的信息來創建對應的對象。
假設有一個配置文件 config.properties
,內容如下:
product.type=ConcreteProductA
創建簡單工廠類 SimpleFactory.java
,用于讀取配置文件并根據配置創建對象:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;public class SimpleFactory { public static Product createProduct() {Properties properties = new Properties();try (InputStream inputStream = SimpleFactory.class.getResourceAsStream("config.properties")) {properties.load(inputStream);String productType = properties.getProperty("product.type");if ("ConcreteProductA".equals(productType)) {return new ConcreteProductA();} else if ("ConcreteProductB".equals(productType)) {return new ConcreteProductB();}} catch (IOException e) {e.printStackTrace();}return null;}
}
在日常開發中,設計模式中的一些常用模式包括:
- 單例模式 (Singleton):用于確保一個類只有一個實例,并提供全局訪問點,例如數據庫連接池、日志系統等。
- 工廠模式 (Factory):用于創建對象的接口,但是由子類決定要實例化的類是哪一個。例如,可以用工廠模式創建各種類型的文件解析器。
- 觀察者模式 (Observer):用于建立對象之間一對多的依賴關系,當一個對象的狀態發生變化時,所有依賴它的對象都會得到通知。例如,GUI界面中的事件監聽器。
- 策略模式 (Strategy):定義一系列算法,將每個算法封裝起來,并使它們可以互換。例如,根據用戶的選擇使用不同的支付策略。
- 裝飾器模式 (Decorator):動態地給一個對象添加一些額外的職責。例如,在圖像處理中可以使用裝飾器來添加濾鏡效果。
- 模板方法模式 (Template Method):定義一個算法的骨架,允許子類為一個或多個步驟提供實現。例如,在構建流程中的各個階段都有固定的步驟,但是具體實現可能不同。