簡單工廠其實並不屬於23種GOF設計模式之一,該模式是工廠方法模式的弱化(或者說是工廠方法模式的一種特例),由於簡單,因此稱爲簡單工廠模式(Simple Factory Pattern),也叫作靜態工廠模式。雖然不是"標準"的設計模式(更像是一種編程習慣),但在實際項目中,採用該方法的案例仍是比較多的。java
簡單工廠模式沒有嚴格的定義,咱們姑且使用如下描述:git
提供一個建立對象實例的功能,而無須關心其具體實現。被建立實例的類型能夠是接口、抽象類,也能夠是具體的類編程
public interface Product { void doSomething(); void doAnything(); } 複製代碼
public class ConcreteProductA implements Product { @Override public void doSomething() { System.out.println("ConcreteProductA doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA doAnything"); } } 複製代碼
public class ConcreteProductB implements Product { @Override public void doSomething() { System.out.println("ConcreteProductB doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB doAnything"); } } 複製代碼
public class Creator { public static Product createProduct(String type) { Product product = null; switch (type) { case "A": product = new ConcreteProductA(); break; case "B": product = new ConcreteProductB(); break; } return product; } } 複製代碼
public class Client { public static void main(String[] args) { Product productA = Creator.createProduct("A"); productA.doSomething(); productA.doAnything(); Product productB = Creator.createProduct("B"); productB.doSomething(); productB.doAnything(); } } 複製代碼
工廠類的擴展比較困難,每增長一個產品,就要在工廠中添加相應的分支,對擴展開放的同時對修改也開放了,不符合開閉原則。若是有不少產品,那麼工廠方法會顯得特別"臃腫",下降可讀性且不易維護。設計模式
Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.markdown
定義一個用於建立對象的接口,讓子類決定實例化哪個類。工廠方法使一個類的實例化延遲到其子類。框架
public interface Product { void doSomething(); void doAnything(); } 複製代碼
public class ConcreteProductA implements Product { @Override public void doSomething() { System.out.println("ConcreteProductA doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA doAnything"); } } 複製代碼
public class ConcreteProductB implements Product { @Override public void doSomething() { System.out.println("ConcreteProductB doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB doAnything"); } } 複製代碼
public interface Creator { Product createProduct(); } 複製代碼
public class ConcreteCreatorA implements Creator { @Override public Product createProduct() { return new ConcreteProductA(); } } 複製代碼
public class ConcreteCreatorB implements Creator { @Override public Product createProduct() { return new ConcreteProductB(); } } 複製代碼
public static void main(String[] args) { Creator creatorA = new ConcreteCreatorA(); Product productA = creatorA.createProduct(); productA.doSomething(); productA.doAnything(); Creator creatorB = new ConcreteCreatorB(); Product productB = creatorB.createProduct(); productB.doSomething(); productB.doAnything(); } 複製代碼
良好的封裝性,代碼結構清晰編輯器
一個對象建立是有條件約束的,如一個調用者須要一個具體的產品對象,只要知道這個產品的類名(或約束字符串)就能夠了,不用知道建立對象的艱辛過程,下降模塊間的耦合。ide
工廠方法模式的擴展性很是優秀oop
在增長產品類的狀況下,只要適當地修改具體的工廠類或擴展一個工廠類,就能夠完成「擁抱變化」。spa
工廠方法模式是典型的解耦框架
高層模塊值須要知道產品的抽象類,其餘的實現類都不用關心,符合迪米特法則,我不須要的就不要去交流;也符合依賴倒置原則,只依賴產品類的抽象;固然也符合里氏替換原則,使用產品子類替換產品父類。
每增長一個產品類,就須要增長一個對應的工廠類,增長了額外的開發量。
利用反射機制來解決"每增長一個產品類,就須要增長一個對應的工廠類"的問題
public interface Creator { <T extends Product> T createProduct(Class<T> clazz); } 複製代碼
public class ConcreteCreator implements Creator { @Override public <T extends Product> T createProduct(Class<T> clazz) { Product product= null; try { product = (Product) Class.forName(clazz.getName()).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return (T) product; } } 複製代碼
public class Client { public static void main(String[] args) { Creator creator = new ConcreteCreator(); Product productA = creator.createProduct(ConcreteProductA.class); productA.doSomething(); productA.doAnything(); Product productB = creator.createProduct(ConcreteProductB.class); productB.doSomething(); productB.doAnything(); } } 複製代碼
工廠方法模式是對簡單工廠的進一步抽象和解耦。和簡單工廠比:
Provide an interface for creating families of related or dependent objects without specifyingtheir concrete classes.
爲建立一組相關或相互依賴的對象提供一個接口,並且無須指定它們的具體類。
產品A家族
public interface ProductA { void doSomething(); void doAnything(); } 複製代碼
產品B家族
public interface ProductB { void doSomething(); void doAnything(); } 複製代碼
產品A家族,產品等級1
public class ConcreteProductA1 implements ProductA { @Override public void doSomething() { System.out.println("ConcreteProductA1 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA1 doAnything"); } } 複製代碼
產品A家族,產品等級2
public class ConcreteProductA2 implements ProductA { @Override public void doSomething() { System.out.println("ConcreteProductA2 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA2 doAnything"); } } 複製代碼
產品B家族,產品等級2
public class ConcreteProductB1 implements ProductB { @Override public void doSomething() { System.out.println("ConcreteProductB1 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB1 doAnything"); } } 複製代碼
產品B家族,產品等級2
public class ConcreteProductB2 implements ProductB { @Override public void doSomething() { System.out.println("ConcreteProductB2 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB2 doAnything"); } } 複製代碼
public interface Creator { /** * 建立A產品家族 * @return */ ProductA createProductA(); /** * 建立B產品家族 * @return */ ProductB createProductB(); // ... // 有N個產品族,在抽象工廠類中就應該有N個建立方法 } 複製代碼
有N個產品族,在抽象工廠類中就應該有N個建立方法
public class ConcreteCreator1 implements Creator { @Override public ProductA createProductA() { return new ConcreteProductA1(); } @Override public ProductB createProductB() { return new ConcreteProductB1(); } } 複製代碼
public class ConcreteCreator2 implements Creator { @Override public ProductA createProductA() { return new ConcreteProductA2(); } @Override public ProductB createProductB() { return new ConcreteProductB2(); } } 複製代碼
有M個產品等級,就應該有M個具體工廠實現
public class Client { public static void main(String[] args) { Creator creator1 = new ConcreteCreator1(); ProductA productA1 = creator1.createProductA(); productA1.doSomething(); productA1.doAnything(); ProductB productB1 = creator1.createProductB(); productB1.doSomething(); productB1.doAnything(); Creator creator2 = new ConcreteCreator2(); ProductA productA2 = creator2.createProductA(); productA2.doSomething(); productA2.doAnything(); ProductB productB2 = creator2.createProductB(); productB2.doSomething(); productB2.doAnything(); } } 複製代碼
封裝性,高層模塊不須要關心每一個產品的實現類,不關心對象是如何建立出來的,只要知道工廠類是誰,就能建立出一個須要的對象
一個產品族中的多個對象被設計成一塊兒工做時,它能保證客戶端始終只使用同一個產品族中的對象,而且很容易交換產品系列
能夠定義產品族內的約束,而且這樣的約束對高層模塊來講是透明的
抽象工廠模式的最大缺點就是產品族擴展很是困難,以上面的通用代碼爲例,若是要增長一個產品C,也就是說產品家族由原來的2個增長到3個,抽象工廠類Creator要增長一個方法createProductC(),而後每一個實現類都要修改,違反了開閉原則。
注意是產品族擴展困難,而不是產品等級,若是新增一個產品等級,只需增長一個具體工廠類的實現便可完成擴展
抽象工廠模式是工廠方法模式的升級版本,在有多個業務品種、業務分類時,經過抽象工廠模式產生須要的對象是一種很是好的解決方式。
工廠方法模式生產一個產品,抽象工廠模式生產多個產品(一系列產品);在編程中,一般表現爲一個接口或者抽象類,也就是說,工廠方法模式提供的全部產品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不一樣的接口或抽象類。
簡單工廠、工廠方法、抽象工廠這三種模式是逐步抽象的,後者適用於更爲通常的場景,而前者是後者的特例。但它們的目標是異曲同工的,目的都是靈活地建立所需的對象而且對客戶端隱藏對象建立細節,三者的擴展性和開發量有所不一樣,能夠根據實際狀況選擇合適的模式來代替以new的方式建立對象的過程:
簡單工廠適用於產品種類較少,且不須要太多擴展的場景
工廠方法模式做爲簡單工廠的進一步抽象和補充,更加適用於有不少擴展需求的場景
若是一個產品族都有相同的約束(在有多個業務品種、業務分類時,即:具備產品族&產品等級結構的概念),則可使用抽象工廠模式
例如一個文本編輯器和一個圖片處理器,都是軟件實體,可是*nix下的文本編輯器和Windows下的文本編輯器雖然功能和界面都相同,可是代碼實現是不一樣的,圖片處理器也有相似狀況。也就是具備了共同的約束條件:操做系統類型。因而咱們可使用抽象工廠模式,產生不一樣操做系統下的編輯器和圖片處理器。
參考文獻:《設計模式之禪》、《大話設計模式》