1. 程式人生 > >「補課」進行時:設計模式(2)——通過一個超級汽車工廠來了解工廠模式

「補課」進行時:設計模式(2)——通過一個超級汽車工廠來了解工廠模式

![](https://cdn.geekdigging.com/DesignPatterns/java_design_pattern.jpg) ## 1. 超級汽車工廠 汽車相信大家都不陌生,我們現在最常用的交通工具得益於在賓士在 1885 年研製的第一輛「三輪車」,就是下面這個傢伙: ![](https://cdn.geekdigging.com/DesignPatterns/02/benz_sanlunche.jpg) 今天我來試一下使用程式通過汽車工廠來造汽車。 ### 1.1 定義一輛汽車 ```java public interface Car { void name(); void drive(); } ``` 身為一輛汽車,首先要有自己的名字,其次是要能開,有了這兩個東西,基本上就能叫一輛汽車了。 ### 1.2 定義一輛特斯拉、一輛賓士、一輛奧迪 ```java public class Tesla implements Car { @Override public void name() { System.out.println("我是特斯拉!!!"); } @Override public void drive() { System.out.println("我是特斯拉,速度賊快!!!"); } } public class Benz implements Car { @Override public void name() { System.out.println("我是賓士!!!"); } @Override public void drive() { System.out.println("我是賓士,內飾豪華!!!"); } } public class Audi implements Car { @Override public void name() { System.out.println("我是奧迪!!!"); } @Override public void drive() { System.out.println("我是奧迪,科技感十足!!!"); } } ``` 這裡定義了三輛汽車,分別實現了他們的父親的兩個方法。 ### 1.3 定義抽象汽車工廠 身為一個超級汽車工廠,當然是要能造汽車,我們建立汽車的時候,肯定是希望直接告訴工廠,我要造一輛特斯拉還是造一輛奧迪。 如果是使用特斯拉或者是奧迪作為輸入引數,那麼建立的方法我們就需要分別寫 3 個了,在 Java 中,這裡可以使用泛型來作為輸入引數,控制引數的輸入型別。 ```java public abstract class AbstractCarFactory { public abstract T createCar(Class clazz); } ``` 這裡使用泛型首先定義了泛型 T 是 Car 的子類,限制了 T 的型別,其次是輸入引數必須是 Class 型別。 ### 1.4 汽車建立工廠 接下來,我們定義一個實際的汽車建立工廠: ```java public class CarFactory extends AbstractCarFactory { @Override public T createCar(Class clazz) { Car car = null; try { car = (T)Class.forName(clazz.getName()).newInstance(); } catch (Exception e) { System.out.println("汽車生產出錯啦,請回爐重造!"); } return (T) car; } } ``` ### 1.5 開始生產汽車 ```java public class Test { public static void main(String[] args) { AbstractCarFactory carFactory = new CarFactory(); System.out.println("-- 第一輛車生產特斯拉 --"); Car tesla = carFactory.createCar(Tesla.class); tesla.name(); tesla.drive(); System.out.println("-- 第二輛車生產賓士 --"); Car benz = carFactory.createCar(Benz.class); benz.name(); benz.drive(); System.out.println("-- 第三輛車生產奧迪 --"); Car audi = carFactory.createCar(Audi.class); audi.name(); audi.drive(); } } ``` 生產的結果如下: ```shell -- 第一輛車生產特斯拉 -- 我是特斯拉!!! 我是特斯拉,速度賊快!!! -- 第二輛車生產賓士 -- 我是賓士!!! 我是賓士,內飾豪華!!! -- 第三輛車生產奧迪 -- 我是奧迪!!! 我是奧迪,科技感十足!!! ``` ## 2. 工廠模式 首先是工廠模式的定義: Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.(定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。) 下面是一個通用類圖: ![](https://cdn.geekdigging.com/DesignPatterns/02/Factory_UML.png) - Product: 用於定義產品特性,實現對事物最抽象的定義,就像上面定義的 Car 。 - ConcreteProduct: 具體對產品定義的實現,就上上面定義的特斯拉和奧迪。 - Creator: 抽象工廠,用於最抽象對 Product 的構造的定義。 - ConcreteCreator: Creator 的具體實現,具體實現如何建立產品類。 ### 2.1 抽象產品類 ```java public abstract class Product { public void method1() { } public abstract void method2(); } ``` ### 2.2 具體產品類 ```java public class ConcreteProduct1 extends Product { @Override public void method2() { } } public class ConcreteProduct2 extends Product { @Override public void method2() { } } ``` 具體的產品類可以有多個,都繼承於抽象的產品類。 ### 2.3 抽象工廠類 ```java public abstract class Creator { public abstract T createProduct(Class clazz); } ``` ### 2.4 具體工廠類 ```java public class ConcreteCreator extends Creator { @Override public T createProduct(Class clazz) { Product product = null; try { product = (Product) Class.forName(clazz.getName()).newInstance(); } catch (Exception e) { // 異常處理 } return (T) product; } } ``` 具體如何產生一個產品的物件的實現,是由具體的工廠類進行實現的,具體的工廠類可以有多個,用於實現多條產品線的生產。 ### 2.5 優點 - 良好的封裝性,程式碼結構清晰。 - 良好的擴充套件性。如果我們需要增加產品類,只需要修改具體的工廠類或者擴充套件一個新的具體工廠類即可。 - 遮蔽產品類。工廠模式是點型的解耦框架,高層次的模組只需要知道產品的抽象類,其他的實現類都不需要關心。 ## 3. 工廠模式擴充套件——多個工廠類 前面說工廠模式可以有多個具體工廠,如果專案複雜度足夠高,將所有的產品都放在一個工廠類中做初始化有點不夠清晰,那麼我們可以實現多個工廠類,由每一個工廠類對應不同的業務規則做對應的產品類的初始化操作。 我如果把上面的那個超級汽車工廠改成多工廠類,先畫一個類圖: ![](https://cdn.geekdigging.com/DesignPatterns/02/More_Factory_UML.png) 這個程式碼我就不寫了,和上面的差不多,就是從原來的一個工廠生產三種車變成了三個專屬工廠生產三