設計模式之簡單工廠模式(simple factory pattern)
什麼是簡單工廠模式, 舉個不恰當的例子, 就說生產雪糕吧, 雪糕什麼形狀的都有, 有長方形,有圓形等等, 怎麼生產呢?
首先肯定是先造個機器, 然後弄幾個按鈕,上面依次寫上長方形, 圓形等等,我按長方形就給我出長方形的, 我按圓形的按鈕就給我出圓形的。
大概就是這樣接下來開始實現
首先肯定要定義什麼是雪糕 連雪糕是什麼都不知道 所以 更別提什麼是長方形雪糕 和圓形雪糕了, 所以要先搞出來他
一般都定義為抽象類或者介面,當父親要有當父親的樣子, 畢竟不管什麼樣的雪糕都是他的孩子。來跟大家sayHello一下
/** * 我是雪糕 */ public abstract class IceCream { public abstract String sayHello(); }
接下來 是圓形雪糕 同樣跟大家sayHello一下
/**
* 我是圓形雪糕
*/
public class CircleIceCream extends IceCream {
@Override
public String sayHello() {
return "我是圓形雪糕, 請多多關照";
}
}
再來個長方形雪糕 sayHello還是要的
/** * 我是長方形雪糕 */ public class RectangleIceCream extends IceCream{ @Override public String sayHello() { return "我是長方形雪糕, 請多多關照"; } }
雪糕有了, 造個機器吧
/** * 雪糕簡單工廠 * 你想要什麼形狀的要告訴我一聲 我跟你生產什麼樣子的, * 請不要超出我的能力範圍, 不然我就罷工了 */ public class IceCreamSimpleFactory { public static IceCream getShapeIceCream(String shape){ if("circle".equals(shape)){ return new CircleIceCream(); }else if("rectangle".equals(shape)){ return new RectangleIceCream(); }else { return null; } } }
造出來的機器還挺有脾氣
接下來開始造雪糕吧, 等不及了
public class IceCreamSimpleFactoryTest {
public static void main(String[] args) {
String warning = "超出機器範圍了, 他罷工了";
IceCream circleIceCream = IceCreamSimpleFactory.getShapeIceCream("circle");
System.out.println(circleIceCream == null ? warning : circleIceCream.sayHello());
IceCream rectangleIceCream = IceCreamSimpleFactory.getShapeIceCream("rectangle");
System.out.println(rectangleIceCream == null ? warning : rectangleIceCream.sayHello());
IceCream heartIceCream = IceCreamSimpleFactory.getShapeIceCream("heart");
System.out.println(heartIceCream == null ? warning : heartIceCream.sayHello());
}
}
雪糕出來了看看結果
我是圓形雪糕, 請多多關照
我是長方形雪糕, 請多多關照
超出機器範圍了, 他罷工了
果然比較笨, 就會兩種形狀的, 給你裝了一大堆零件就給我造出來兩種, 丟人啊,
而且我要是還想生產個別的形狀的還要給你加零件, 都是錢啊, 唉 改造一下, 能不能弄成一勞永逸的
package com.yxw.simplefactory;
/**
* 通過反射改造工廠類, 一勞永逸
*/
public class IceCreamReflectSimpleFactory {
/**
* 你讓我造各種各樣的雪糕, 首先你必須是雪糕,
* 你要讓我造圓形豆沙包, 對不起,我真幹不了
* 就算真幹得了, 我也不能給你, 因為我越線了
* @param shape
* @return
*/
public static IceCream getShapeIceCream(String shape){
try {
/**
* 通過反射例項化物件, newInstance()預設呼叫無參構造方法
*/
Object object = Class.forName(shape).newInstance();
if(object instanceof IceCream){
return (IceCream)object;
}
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (ClassNotFoundException e) {
}
return null;
}
}
試一下子
package com.yxw.simplefactory;
public class IceCreamReflectSimpleFactoryTest {
public static void main(String[] args) {
String warning = "不好意思, 真幹不了";
IceCream circleIceCream = IceCreamReflectSimpleFactory.getShapeIceCream(CircleIceCream.class.getName());
System.out.println(circleIceCream == null ? warning : circleIceCream.sayHello());
IceCream rectangelIceCream = IceCreamReflectSimpleFactory.getShapeIceCream(RectangleIceCream.class.getName());
System.out.println(rectangelIceCream == null ? warning : rectangelIceCream.sayHello());
IceCream heart = IceCreamReflectSimpleFactory.getShapeIceCream("heart");
System.out.println(heart == null ? warning : heart.sayHello());
}
}
/**
* 測試結果:
* 我是圓形雪糕, 請多多關照
* 我是長方形雪糕, 請多多關照
* 不好意思, 真幹不了
*/
挺好 改造後果然省了不少零件, 敗家玩意,下次再加別的形狀就不用動你了 就這最後一次了。
ok 接下來化比較官方, 如果你理解了 就別浪費時間往下看了
簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式,它屬於類建立型模式。在簡單工廠模式中,可以根據引數的不同返回不同類的例項。簡單工廠模式專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。
模式結構:
工廠角色
工廠角色負責實現建立所有例項的內部邏輯
抽象產品角色
抽象產品角色是所建立的所有物件的父類,負責描述所有例項所共有的公共介面
具體產品角色
具體產品角色是建立目標,所有建立的物件都是抽象產品角色的子類
-
將物件的建立和物件本身業務處理分離可以降低系統的耦合度,使得兩者修改起來都相對容易。
-
在呼叫工廠類的工廠方法時,由於工廠方法是靜態方法,使用起來很方便,可通過類名直接呼叫,而且只需要傳入一個簡單的引數即可,在實際開發中,還可以在呼叫時將所傳入的引數儲存在XML等格式的配置檔案中,修改引數時無須修改任何原始碼。
-
簡單工廠模式最大的問題在於工廠類的職責相對過重,增加新的產品需要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的。
-
簡單工廠模式的要點在於:當你需要什麼,只需要傳入一個正確的引數,就可以獲取你所需要的物件,而無須知道其建立細節。
-
工廠類含有必要的判斷邏輯,可以決定在什麼時候建立哪一個產品類的例項,客戶端可以免除直接建立產品物件的責任,而僅僅“消費”產品;簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用於建立物件。
-
客戶端無須知道所建立的具體產品類的類名,只需要知道具體產品類所對應的引數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
-
通過引入配置檔案,可以在不修改任何客戶端程式碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
-
由於工廠類集中了所有產品建立邏輯,一旦不能正常工作,整個系統都要受到影響。
-
使用簡單工廠模式將會增加系統中類的個數,在一定程式上增加了系統的複雜度和理解難度。
-
系統擴充套件困難,一旦新增新產品就不得不修改工廠邏輯,在產品型別較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴充套件和維護。
-
簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。
在以下情況下可以使用簡單工廠模式:
-
工廠類負責建立的物件比較少:由於建立的物件較少,不會造成工廠方法中的業務邏輯太過複雜。
-
客戶端只知道傳入工廠類的引數,對於如何建立物件不關心:客戶端既不需要關心建立細節,甚至連類名都不需要記住,只需要知道型別所對應的引數。
-
JDK類庫中廣泛使用了簡單工廠模式,如工具類java.text.DateFormat,它用於格式化一個本地日期或者時間。
-
建立型模式對類的例項化過程進行了抽象,能夠將物件的建立與物件的使用過程分離。
-
簡單工廠模式又稱為靜態工廠方法模式,它屬於類建立型模式。在簡單工廠模式中,可以根據引數的不同返回不同類的例項。簡單工廠模式專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。
-
簡單工廠模式包含三個角色:工廠角色負責實現建立所有例項的內部邏輯;抽象產品角色是所建立的所有物件的父類,負責描述所有例項所共有的公共介面;具體產品角色是建立目標,所有建立的物件都充當這個角色的某個具體類的例項。
-
簡單工廠模式的要點在於:當你需要什麼,只需要傳入一個正確的引數,就可以獲取你所需要的物件,而無須知道其建立細節。
-
簡單工廠模式最大的優點在於實現物件的建立和物件的使用分離,將物件的建立交給專門的工廠類負責,但是其最大的缺點在於工廠類不夠靈活,增加新的具體產品需要修改工廠類的判斷邏輯程式碼,而且產品較多時,工廠方法程式碼將會非常複雜。
-
簡單工廠模式適用情況包括:工廠類負責建立的物件比較少;客戶端只知道傳入工廠類的引數,對於如何建立物件不關心
參考資料