設計模式之工廠模式
1. 簡介
工廠模式(Factory Pattern)是開發中比較常用的設計模式之一.
工廠模式(Factory Pattern)簡單點了解就是建立對象的模式,比如使用頻率最高的單例模式就是建立型模式的一種。
這種類型的設計模式屬于建立型模式(提供了一種在建立對象的同時隐藏建立邏輯的方式,而不是使用 new 運算符直接執行個體化對象。這使得程式在判斷針對某個給定執行個體需要建立哪些對象時更加靈活)。
2. 類别
工廠模式(Factory Pattern)可以分為三種,分别是:
- 簡單工廠模式
- 工廠方法模式
- 抽象工廠模式
後面的兩種模式都是基于第一種模式進行的。
3. 簡單工廠模式
3.1 需求
支付寶推廣螞蟻森林,假設要在庫布其種植樹苗(梭梭樹、樟子松、胡楊等),根據使用者兌換的幼苗,螞蟻森林會進行對應幼苗的擷取、挖坑、入坑、填土、澆水。
3.2 普通實作方式
3.2.1 由于有多種樹苗,是以首先設計一個接口Tree來表示樹苗(該類具有幼苗的擷取、挖坑、入坑、填土、澆水等功能),接着定義多個Tree的實作類來實作相應樹的接口功能。下面定義樹接口Tree及其3個接口實作類PinusSylvestrisVar、Populus、sacsaoul。
/** 樹接口 */
public interface Tree {
/** 擷取幼苗 */
public void getSeedling();
/** 挖坑 */
public void digHollow();
/** 幼苗入坑 */
public void putSeedingIntoHollow();
/** 填土 */
public void fillSoil();
/** 澆水 */
public void watering();
}
/** 樟子松 */
public class PinusSylvestrisVar implements Tree {
@Override
public void getSeedling() {
System.out.println("擷取樟子松幼苗。");
}
@Override
public void digHollow() {
System.out.println("挖适合種樟子松幼苗的坑。");
}
@Override
public void putSeedingIntoHollow() {
System.out.println("将樟子松幼苗放入坑中。");
}
@Override
public void fillSoil() {
System.out.println("給樟子松幼苗填土。");
}
@Override
public void watering() {
System.out.println("給樟子松幼苗澆水。");
}
}
/** 胡楊 */
public class Populus implements Tree {
@Override
public void getSeedling() {
System.out.println("擷取胡楊幼苗。");
}
@Override
public void digHollow() {
System.out.println("挖适合種胡楊幼苗的坑。");
}
@Override
public void putSeedingIntoHollow() {
System.out.println("将胡楊幼苗放入坑中。");
}
@Override
public void fillSoil() {
System.out.println("給胡楊幼苗填土。");
}
@Override
public void watering() {
System.out.println("給胡楊幼苗澆水。");
}
}
/** 梭梭樹 */
public class sacsaoul implements Tree {
@Override
public void getSeedling() {
System.out.println("擷取梭梭幼苗。");
}
@Override
public void digHollow() {
System.out.println("挖适合種梭梭幼苗的坑。");
}
@Override
public void putSeedingIntoHollow() {
System.out.println("将梭梭幼苗放入坑中。");
}
@Override
public void fillSoil() {
System.out.println("給梭梭幼苗填土。");
}
@Override
public void watering() {
System.out.println("給梭梭幼苗澆水。");
}
}
3.2.2 接下來需要根據使用者的選擇進行對應樹苗的擷取、挖坑、入坑、填土、澆水等操作,是以需要定義一個TreeStoreSimple類,其中有一個方法plantTheTree将這些操作包含進去。
public class TreeStoreSimple {
public void plantTheTree(String treeType) throws Exception {
Tree tree = null;
switch(treeType) {
case "PinusSylvestrisVar": tree = new PinusSylvestrisVar();break;
case "Populus": tree = new Populus();break;
case "sacsaoul": tree = new sacsaoul();break;
default: throw new Exception("樹類型不準确!");
}
tree.getSeedling();
tree.digHollow();
tree.putSeedingIntoHollow();
tree.fillSoil();
tree.watering();
}
}
3.2.3 上面代碼有一個很明顯的問題,假設除了TreeStoreSimple以外的一個A類也要根據樹類型擷取相應的樹對象,那麼switch中的代碼也要再寫一遍,如果螞蟻森林要新增一個樹種“沙柳”,就必須将TreeStoreSimple與A中的相應代碼進行修改,這樣不利于代碼維護,增加了維護成本。是以,此處就可以使用簡單工廠模式進行實作。
3.3 簡單工廠模式實作方式
專門建立一個SimpleTreeFactory類将建立Tree對象的過程單獨剝離開來。
public class SimpleTreeFactory {
public Tree createTree(String treeType) throws Exception {
Tree tree = null;
switch(treeType) {
case "PinusSylvestrisVar": tree = new PinusSylvestrisVar();break;
case "Populus": tree = new Populus();break;
case "sacsaoul": tree = new sacsaoul();break;
default: throw new Exception("樹類型不準确!");
}
return tree;
}
}
修改TreeStoreSimple類
public class TreeStoreSimpleFactory {
SimpleTreeFactory stf;
public TreeStoreSimple(SimpleTreeFactory stf) {
this.stf = stf;
}
public void plantTheTree(String treeType) throws Exception {
Tree tree = stf.createTree(treeType);
tree.getSeedling();
tree.digHollow();
tree.putSeedingIntoHollow();
tree.fillSoil();
tree.watering();
}
public static void main(String[] args) {
try {
SimpleTreeFactory stf = new SimpleTreeFactory();
TreeStoreSimple ts = new TreeStoreSimple(stf);
ts.plantTheTree("PinusSylvestrisVar");
} catch (Exception e) {
e.printStackTrace();
}
}
}
看了上述的案例,現在我們來總結一下:其實簡單工廠不是一個設計模式,反而比較像一種程式設計習慣,将建立對象的過程從對象使用者中分離開來,這樣就可以通過簡單工廠專門負責建立産品了。在上面的例子中,SimpleTreeFactory就是專門負責建立産品的簡單工廠。
4. 工廠方法模式
在工廠方法模式中,定義了一個建立對象的接口,但由子類決定要執行個體化的類是哪一個。
工廠方法讓類把執行個體化推遲到子類。選擇了使用哪個子類,自然就決定了實際建立的産品是什麼。工廠方法模式通過讓子類決定建立的對象是什麼,來達到将對象建立的過程封裝的目的。以下是代碼(其中的Tree及其3個接口實作類PinusSylvestrisVar、Populus、sacsaoul參考3中的實作):
public interface TreeFactory {
/** 擷取Tree對象 */
Tree createTree();
}
public class PinusSylvestrisVarFactory implements TreeFactory {
@Override
public Tree createTree() {
return new PinusSylvestrisVar();
}
}
public class PopulusFactory implements TreeFactory {
@Override
public Tree createTree() {
return new Populus();
}
}
public class SacsaoulFactory implements TreeFactory {
@Override
public Tree createTree() {
return new Sacsaoul();
}
}
public class TreeStoreMethod {
TreeFactory tf;
public TreeStoreMethod(TreeFactory tf) {
this.tf = tf;
}
public void plantTheTree() throws Exception {
Tree tree = tf.createTree();
tree.getSeedling();
tree.digHollow();
tree.putSeedingIntoHollow();
tree.fillSoil();
tree.watering();
}
public static void main(String[] args) {
try {
PinusSylvestrisVarFactory psvf = new PinusSylvestrisVarFactory();
TreeStoreMethod tsm = new TreeStoreMethod(psvf);
tsm.plantTheTree();
System.out.println("-----------------------");
PopulusFactory pf = new PopulusFactory();
tsm = new TreeStoreMethod(pf);
tsm.plantTheTree();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. 抽象工廠模式
提供一個建立一系列相關或互相依賴對象的接口,而無需指定它們具體的類,是工廠方法模式的更新版本。
抽象工廠模式有一個缺點在于如果我們需要新增一個産品,就需要修改接口及其所有的實作類,這可能是一項很繁重的工作。
抽象工廠模式側重一個工廠可以建立一組相關的對象;但是這組相關對象是平等地位,沒有主次之分,也沒有整體與部分的概念,如何使用由客戶決定;
相關代碼實作以後再說吧。
參考連結
設計模式之死磕工廠模式(原創)
設計模式——工廠模式
設計模式之抽象工廠模式
最後,謝謝各位讀者的耐心閱讀,如有語句不通順或者不準确的地方,還請指正!謝謝!(__)