簡單工廠其實並不屬於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.框架
定義一個用於建立對象的接口,讓子類決定實例化哪個類。工廠方法使一個類的實例化延遲到其子類。編輯器
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
一個對象建立是有條件約束的,如一個調用者須要一個具體的產品對象,只要知道這個產品的類名(或約束字符串)就能夠了,不用知道建立對象的艱辛過程,下降模塊間的耦合。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下的文本編輯器雖然功能和界面都相同,可是代碼實現是不一樣的,圖片處理器也有相似狀況。也就是具備了共同的約束條件:操做系統類型。因而咱們可使用抽象工廠模式,產生不一樣操做系統下的編輯器和圖片處理器。
參考文獻:《設計模式之禪》、《大話設計模式》