4 方案的改進
Sunny軟體公司開發人員發現在建立具體Chart對象時,每更換一個Chart對象都需要修改用戶端代碼中靜態Factory 方法的參數,用戶端代碼將要重新編譯,這對於用戶端而言,違反了“開閉原則”,有沒有一種方法能夠在不修改用戶端代碼的前提下更換具體產品對象呢。答案是肯定的,下面將介紹一種常用的實現方式。
我們可以將靜態Factory 方法的參數儲存在XML或properties格式的設定檔中,如下config.xml所示:
<?xml version="1.0"?><config><chartType>histogram</chartType></config>
再通過一個工具類XMLUtil來讀取設定檔中的字串參數,XMLUtil類的代碼如下所示:
import javax.xml.parsers.*;import org.w3c.dom.*;import org.xml.sax.SAXException;import java.io.*;public class XMLUtil { //該方法用於從XML設定檔中提取圖表類型,並傳回型別名public static String getChartType() {try {//建立文檔對象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File("config.xml")); //擷取包含圖表類型的文本節點NodeList nl = doc.getElementsByTagName("chartType"); Node classNode = nl.item(0).getFirstChild(); String chartType = classNode.getNodeValue().trim(); return chartType; } catch(Exception e) { e.printStackTrace(); return null; } }}
在引入了設定檔和工具類XMLUtil之後,用戶端代碼修改如下:
class Client {public static void main(String args[]) {Chart chart;String type = XMLUtil.getChartType(); //讀取設定檔中的參數chart = ChartFactory.getChart(type); //建立產品對象chart.display();}}
不難發現,在上述用戶端代碼中不包含任何與具體圖表對象相關的資訊,如果需要更換具體圖表對象,只需修改設定檔config.xml,無須修改任何原始碼,符合“開閉原則”。
思考
在簡單原廠模式中增加新的具體產品時是否符合“開閉原則”。如果不符合,原有系統需作出哪些修改。
5 簡單原廠模式的簡化
有時候,為了簡化簡單原廠模式,我們可以將抽象產品類和工廠類合并,將靜態Factory 方法移至抽象產品類中,如圖3所示:
圖3 簡化的簡單原廠模式
在圖3中,用戶端可以通過產品父類的靜態Factory 方法,根據參數的不同建立不同類型的產品子類對象,這種做法在JDK等類庫和架構中也廣泛存在。
6 簡單原廠模式總結
簡單原廠模式提供了專門的工廠類用於建立對象,將對象的建立和對象的使用分離開,它作為一種最簡單的原廠模式在軟體開發中得到了較為廣泛的應用。
1. 主要優點
簡單原廠模式的主要優點如下:
(1) 工廠類包含必要的判斷邏輯,可以決定在什麼時候建立哪一個產品類的執行個體,用戶端可以免除直接建立產品對象的職責,而僅僅“消費”產品,簡單原廠模式實現了對象建立和使用的分離。
(2) 用戶端無須知道所建立的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些複雜的類名,通過簡單原廠模式可以在一定程度減少使用者的記憶量。
(3) 通過引入設定檔,可以在不修改任何用戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
2. 主要缺點
簡單原廠模式的主要缺點如下:
(1) 由於工廠類集中了所有產品的建立邏輯,職責過重,一旦不能正常工作,整個系統都要受到影響。
(2) 使用簡單原廠模式勢必會增加系統中類的個數(引入了新的工廠類),增加了系統的複雜度和理解難度。
(3) 系統擴充困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴充和維護。
(4) 簡單原廠模式由於使用了靜態Factory 方法,造成工廠角色無法形成基於繼承的等級結構。
3. 適用情境
在以下情況下可以考慮使用簡單原廠模式:
(1) 工廠類負責建立的對象比較少,由於建立的對象較少,不會造成Factory 方法中的商務邏輯太過複雜。
(2) 用戶端只知道傳入工廠類的參數,對於如何建立對象並不關心。
練習
使用簡單原廠模式設計一個可以建立不同幾何形狀(如圓形、方形和三角形等)的繪圖工具,每個幾何圖形都具有繪製draw()和擦除erase()兩個方法,要求在繪製不支援的幾何圖形時,提示一個UnSupportedShapeException。
【作者:劉偉 http://blog.csdn.net/lovelion】