Java設計模式—工廠方法模式&抽象工廠模式
工廠方法模式與抽象工廠模式都是設計模式中重要而且常見的模式。
工廠方法模式:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。
通用類圖如下:
在工廠方法模式中,抽象產品類Product負責定義產品的共性,實現對事物最抽象的定義;Creator為抽象建立
類,也就是抽象工廠,具體如何建立產品類是由具體的實現工廠ConcreteCreator完成的。
工廠方法模式的擴充套件方式有很多種,下邊是工廠方法模式一個比較實用的原始碼:
抽象產品類:
- public abstract class Product {
- //產品類的公共方法
- public void method1(){
- //業務邏輯處理
- }
- //抽象方法
- public abstract void method2();
- }
具體的產品類可以有多個,都繼承於抽象產品類。
- public class ConcreteProduct1 extends Product {
- public void method2() {
- //業務邏輯處理
- }
- }
- public class ConcreteProduct2 extends Product {
- public void method2() {
- //業務邏輯處理
- }
- }
抽象工廠類負責定義產品物件的產生:
[java] view plain copy- public abstract class Creator {
- /*
- * 建立一個產品物件,其輸入引數型別可以自行設定
- * 通常為String、Enum、Class等,當然也可以為空
- */
- public abstract <T extends Product> T createProduct(Class<T> c);
- }
具體如何產生一個產品的物件,是由具體的工廠類實現的:
- public class ConcreteCreator extends Creator {
- public <T extends Product> T createProduct(Class<T> c){
- Product product=null;
- try {
- product = (Product)Class.forName(c.getName()).newInstance();
- } catch (Exception e) {
- //異常處理
- }
- return (T)product;
- }
- }
場景類如下所示: [java] view plain copy
- public class Client {
- public static void main(String[] args) {
- Creator creator = new ConcreteCreator();
- Product product = creator.createProduct(ConcreteProduct1.class);
- /*
- * 繼續業務處理
- */
- }
- }
該通用程式碼是一個比較實用、易擴充套件的框架。
工廠方法模式的優點:
(1)良好的封裝性,程式碼結構清晰。一個物件建立是有條件約束的,如一個呼叫者需要一個具體的產品物件,只要
知道這個產品的類名(或約束字串)就可以了,不用知道建立物件的艱辛過程,降低模組間的耦合。
(2)工廠方法模式的擴充套件性非常優秀。在增加產品類的情況下,只要適當地修改具體的工廠類或擴充套件一個工廠類,
就可以完成“擁抱變化”。
(3)遮蔽產品類。這一特點非常重要,產品類的實現如何變化,呼叫者都不需要關心,它只需要關心產品的介面,
只要介面保持不變,系統中的上層模組就不要發生變化。因為產品類的例項化工作是由工廠類負責的,一個產品物件
具體由哪一個產品生成是由工廠類決定的。
使用場景:
首先,工廠方法模式是new一個物件的替代品,所以在所有需要生成物件的地方都可以使用,但是需要慎重地考
慮是否要增加一個工廠類進行管理,增加程式碼的複雜度。
工廠方法模式的擴充套件:
(1)簡單工廠模式
當一個模組只需要一個工工廠類時,我們可以將抽象工廠類kill掉,然後將具體工廠類中製造產品的方法前面加static
關鍵字,則,工廠方法模式就變為了簡單工廠模式。
該模式是工廠方法模式的弱化,因為簡單,所以稱為簡單工廠模式(Simple Factory Pattern),也叫做靜態工
廠模式。在實際專案中,採用該方法的案例還是比較多的,其缺點是工廠類的擴充套件比較困難,不符合開閉原則,但它
仍然是一個非常實用的設計模式。
(2)多工廠模式
當遇到一個複雜的專案,初始化一個物件很費事的時候,我們可以使用多工廠模式,即一個工廠只生產特定的某種產
品,實現了單一職責。每一個產品類都對應了一個建立類,好處就是建立類的職責清晰,而且結構簡單,但是給可擴充套件性和可維護性帶來了一定的影響。為什麼這麼說呢?如果要擴充套件一個產品類,就需要建立一個相應的工廠類,這樣就增加了擴充套件的難度。因為工廠類和產品類的數量相同,維護時需要考慮兩個物件之間的關係。
當然,在複雜的應用中一般採用多工廠的方法,然後再增加一個協調類,避免呼叫者與各個子工廠交流,協調類
的作用是封裝子工廠類,對高層模組提供統一的訪問介面。
抽象工廠模式
抽象工廠模式是一種比較常用的模式。
其定義如下:
為建立一組相關或相互依賴的物件提供一個介面,而且無須指定它們的具體類。
通用類圖如下:
抽象工廠模式是工廠方法模式的升級版本,在有多個業務品種、業務分類時,通過抽象工廠模式產生需要的
物件是一種非常好的解決方式。我們來看看抽象工廠的通用原始碼,首先有兩個互相影響的產品線(也叫做產族),
例如製造汽車的左側門和右側門,這兩個應該是數量相等的——兩個物件之間的約束,每個型號的車門都是不
一樣的,這是產品等級結構約束的,我們先看看兩個產品族的類圖,如下所示:
注意類圖上的圈圈、框框相對應,兩個抽象的產品類可以有關係,例如共同繼承或實現一個抽象類或介面。
通用原始碼如下:
[java] view plain copy- //抽象產品類
- public abstract class AbstractProductA {
- //每個產品共有的方法
- public void shareMethod(){
- }
- //每個產品相同方法,不同實現
- public abstract void doSomething();
- }
[java] view plain copy
- public class ProductA1 extends AbstractProductA {
- public void doSomething() {
- System.out.println("產品A1的實現方法");
- }
- }
- 產品A2的實現類
- public class ProductA2 extends AbstractProductA {
- public void doSomething() {
- System.out.println("產品A2的實現方法");
- }
- }
- 抽象工廠類
- public abstract class AbstractCreator {
- //建立A產品家族
- public abstract AbstractProductA createProductA();
- //建立B產品家族
- public abstract AbstractProductB createProductB();
- }
注意:有N個產品族,在抽象工廠類中就應該有N個建立方法。
[java] view plain copy
- 產品等級1的實現類
- public class Creator1 extends AbstractCreator {
- //只生產產品等級為1的A產品
- public Abstract ProductA createProductA() {
- return new ProductA1();
- }
- //只生產產品等級為1的B產品
- public AbstractProductB createProductB() {
- return new ProductB1();
- }
- }
[java] view plain copy
- 產品等級2的實現類
- public class Creator2 extends AbstractCreator {
- //只生產產品等級為2的A產品
- public AbstractProductA createProductA() {
- return new ProductA2();
- }
- //只生產產品等級為2的B產品
- public AbstractProductB createProductB() {
- return new ProductB2();
- }
- }
場景類如下:
[java] view plain copy- public class Client {
- public static void main(String[] args) {
- //定義出兩個工廠
- Abstract Creator creator1 = new Creator1();
- Abstract Creator creator2 = new Creator2();
- //產生A1物件
- AbstractProductA a1 = creator1.createProductA();
- //產生A2物件
- AbstractProductA a2 = creator2.createProductA();
- //產生B1物件
- AbstractProductB b1 = creator1.createProductB();
- //產生B2物件
- AbstractProductB b2 = creator2.createProductB();
- /*
- * 然後在這裡就可以為所欲為了...
- */
- }
- }
抽象工廠模式的優點:
● 封裝性。
每個產品的實現類不是高層模組要關心的,它要關心的是什麼?是介面,是抽象,它不關心物件是如何創建出
來,這由誰負責呢?工廠類,只要知道工廠類是誰,我就能創建出一個需要的物件,省時省力,優秀設計就應該如
此。
● 產品族內的約束為非公開狀態。
缺點:
抽象工廠模式的最大缺點就是產品族擴充套件非常困難,為什麼這麼說呢?我們以通用程式碼為例,如果要增加一個產
品C,也就是說產品家族由原來的2個增加到3個,看看我們的程式有多大改動吧!抽象類AbstractCreator要增加一個
方法createProductC(),然後兩個實現類都要修改,想想看,這嚴重違反了開閉原則,而且我們一直說明抽象類和接
口是一個契約。改變契約,所有與契約有關係的程式碼都要修改,那麼這段程式碼叫什麼?叫“有毒程式碼”,——只要與這
段程式碼有關係,就可能產生侵害的危險!
兩種設計模式的區別:
區別在於產品,如果產品單一,最合適用工廠模式,但是如果有多個業務品種、業務分類時,通過抽象工廠模式產生需要的物件是一種非常好的解決方式。再通俗深化理解下:工廠模式針對的是一個產品等級結構 ,抽象工廠模式針對的是面向多個產品等級結構的。
工廠方法模式與抽象工廠模式對比:
工廠方法模式 |
抽象工廠模式 |
針對的是一個產品等級結構 | 針對的是面向多個產品等級結構 |
一個抽象產品類 | 多個抽象產品類 |
可以派生出多個具體產品類 | 每個抽象產品類可以派生出多個具體產品類 |
一個抽象工廠類,可以派生出多個具體工廠類 | 一個抽象工廠類,可以派生出多個具體工廠類 |
每個具體工廠類只能建立一個具體產品類的例項 | 每個具體工廠類可以建立多個具體產品類的例項 |