鍍金池/ 教程/ Java/ 工廠三兄弟之簡單工廠模式(四)
工廠三兄弟之抽象工廠模式(五)
復(fù)雜對象的組裝與創(chuàng)建——建造者模式(一)
工廠三兄弟之工廠方法模式(一)
復(fù)雜對象的組裝與創(chuàng)建——建造者模式(二)
確保對象的唯一性——單例模式 (二)
工廠三兄弟之簡單工廠模式(四)
確保對象的唯一性——單例模式 (一)
工廠三兄弟之工廠方法模式(四)
對象的克隆——原型模式(一)
工廠三兄弟之抽象工廠模式(二)
工廠三兄弟之工廠方法模式(三)
工廠三兄弟之抽象工廠模式(一)
工廠三兄弟之抽象工廠模式(四)
確保對象的唯一性——單例模式 (三)
工廠三兄弟之簡單工廠模式(三)
對象的克隆——原型模式(二)
復(fù)雜對象的組裝與創(chuàng)建——建造者模式(三)
對象的克隆——原型模式(四)
確保對象的唯一性——單例模式(四)
工廠三兄弟之簡單工廠模式(一)
工廠三兄弟之簡單工廠模式(二)
對象的克隆——原型模式(三)
工廠三兄弟之抽象工廠模式(三)
確保對象的唯一性——單例模式(五)
工廠三兄弟之工廠方法模式(二)

工廠三兄弟之簡單工廠模式(四)

方案的改進

Sunny 軟件公司開發(fā)人員發(fā)現(xiàn)在創(chuàng)建具體 Chart 對象時,每更換一個 Chart 對象都需要修改客戶端代碼中靜態(tài)工廠方法的參數(shù),客戶端代碼將要重新編譯,這對于客戶端而言,違反了“開閉原則”,有沒有一種方法能夠在不修改客戶端代碼的前提下更換具體產(chǎn)品對象呢?答案是肯定的,下面將介紹一種常用的實現(xiàn)方式。

我們可以將靜態(tài)工廠方法的參數(shù)存儲在 XML 或 properties 格式的配置文件中,如下 config.xml 所示:

<?xml version="1.0"?>
<config>
    <chartType>histogram</chartType>
</config>

再通過一個工具類 XMLUtil 來讀取配置文件中的字符串參數(shù),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 {
            //創(chuàng)建文檔對象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;                           
            doc = builder.parse(new File("config.xml")); 

            //獲取包含圖表類型的文本節(jié)點
            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(); //讀取配置文件中的參數(shù)
        chart = ChartFactory.getChart(type); //創(chuàng)建產(chǎn)品對象
        chart.display();
    }
}

不難發(fā)現(xiàn),在上述客戶端代碼中不包含任何與具體圖表對象相關(guān)的信息,如果需要更換具體圖表對象,只需修改配置文件 config.xml,無須修改任何源代碼,符合“開閉原則”。

思考

在簡單工廠模式中增加新的具體產(chǎn)品時是否符合“開閉原則”?如果不符合,原有系統(tǒng)需作出哪些修改?

簡單工廠模式的簡化

有時候,為了簡化簡單工廠模式,我們可以將抽象產(chǎn)品類和工廠類合并,將靜態(tài)工廠方法移至抽象產(chǎn)品類中,如圖所示:

http://wiki.jikexueyuan.com/project/design-pattern-creation/images/20130711145238171.jpg" alt="簡化的簡單工廠模式" />

在圖中,客戶端可以通過產(chǎn)品父類的靜態(tài)工廠方法,根據(jù)參數(shù)的不同創(chuàng)建不同類型的產(chǎn)品子類對象,這種做法在 JDK 等類庫和框架中也廣泛存在。

簡單工廠模式總結(jié)

簡單工廠模式提供了專門的工廠類用于創(chuàng)建對象,將對象的創(chuàng)建和對象的使用分離開,它作為一種最簡單的工廠模式在軟件開發(fā)中得到了較為廣泛的應(yīng)用。

主要優(yōu)點

簡單工廠模式的主要優(yōu)點如下:

(1) 工廠類包含必要的判斷邏輯,可以決定在什么時候創(chuàng)建哪一個產(chǎn)品類的實例,客戶端可以免除直接創(chuàng)建產(chǎn)品對象的職責(zé),而僅僅“消費”產(chǎn)品,簡單工廠模式實現(xiàn)了對象創(chuàng)建和使用的分離。

(2) 客戶端無須知道所創(chuàng)建的具體產(chǎn)品類的類名,只需要知道具體產(chǎn)品類所對應(yīng)的參數(shù)即可,對于一些復(fù)雜的類名,通過簡單工廠模式可以在一定程度減少使用者的記憶量。

(3) 通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產(chǎn)品類,在一定程度上提高了系統(tǒng)的靈活性。

主要缺點

簡單工廠模式的主要缺點如下:

(1) 由于工廠類集中了所有產(chǎn)品的創(chuàng)建邏輯,職責(zé)過重,一旦不能正常工作,整個系統(tǒng)都要受到影響。

(2) 使用簡單工廠模式勢必會增加系統(tǒng)中類的個數(shù)(引入了新的工廠類),增加了系統(tǒng)的復(fù)雜度和理解難度。

(3) 系統(tǒng)擴展困難,一旦添加新產(chǎn)品就不得不修改工廠邏輯,在產(chǎn)品類型較多時,有可能造成工廠邏輯過于復(fù)雜,不利于系統(tǒng)的擴展和維護。

(4) 簡單工廠模式由于使用了靜態(tài)工廠方法,造成工廠角色無法形成基于繼承的等級結(jié)構(gòu)。

適用場景

在以下情況下可以考慮使用簡單工廠模式:

(1) 工廠類負(fù)責(zé)創(chuàng)建的對象比較少,由于創(chuàng)建的對象較少,不會造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜。

(2) 客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象并不關(guān)心。

練習(xí)

使用簡單工廠模式設(shè)計一個可以創(chuàng)建不同幾何形狀(如圓形、方形和三角形等)的繪圖工具,每個幾何圖形都具有繪制 draw() 和擦除 erase() 兩個方法,要求在繪制不支持的幾何圖形時,提示一個 UnSupportedShapeException。