設計模式之簡單工廠模式(1.1)

簡單工廠模式:
簡單工廠模式不屬於Gof23種設計模式,通常所說的工廠模式是指的工廠方法模式
簡單工廠模式是作爲其他工廠模式的入門
簡單工廠模式---> 工廠方法模式---> 抽象工廠模式

一:
需求:公司圖表庫設計人員希望爲應用系統開發人員提供一套靈活易用的圖表庫, 而且可以較爲方便地對圖表庫進行擴展, 以便能夠在將來增加一些新類型的圖表。設計人員提出了一個初始設計方案, 將所有圖表的實現代碼封裝在一個Chart類中

1.1僞代碼如下

class Chart {
	private String type; // 圖表類型

	public Chart(Object[][] data, String type) {
		this.type = type;
		if (type.equalsIgnoreCase("histogram")) {
			//初始化柱狀圖
		}else if (type.equalsIgnoreCase("pie")) {
			//初始化餅狀圖
		}else if (type.equalsIgnoreCase("line")) {
			//初始化折線圖
		}
	}

	public void display() {
		if (this.type.equalsIgnoreCase("histogram")) {
			//顯示柱狀圖
		}else if (this.type.equalsIgnoreCase("pie")) {
			//顯示餅狀圖
		}else if (this.type.equalsIgnoreCase("line")) {
			//顯示折線圖
		}
	}
}

1.2僞代碼缺點
1.在Chart類中包含很多if..else 代碼塊,整個類代碼相當冗長,代碼越長,閱讀難度,維護難度和測試難度越大
2.Chart類的職責過重,將各種圖表對象的初始化代碼和顯示代碼集中在一個類中實現,違反了"單一職責原則"
3.當需要增加新類型的圖表時,必須修改Chart類的源代碼,違反了開閉原則!
4.客戶端只能通過new關鍵字來直接創建Chart對象,Chart類與客戶端類耦合度較高,對象的創建和使用無法分離

1.3如何解決
面對如此巨大,職責如此重,而且與客戶端代碼耦合度非常高的類,我們該怎麼辦?接下來使用簡單工廠模式來解決!

1.4簡單工廠模式定義如下:
定義一個工廠類,它可以根據參數的不同返回不同類的實例,被創建的實例通常都具有共同的父類
因爲在簡單工廠模式中用於創建實例的方法是靜態(static)方法, 
因此簡單工廠模式又被稱爲靜態工廠方法(Static Factory Method)模式, 
它屬於類創建型模式

簡單工廠模式:一般有三個角色:
抽象產品角色
具體產品角色
工廠角色

1.5完整解決方案
爲了將Chart類的職責分離, 同時將Chart對象的創建和使用分離,決定使用簡單工廠模式對圖表庫進行重構
a.抽象產品角色:

public interface Chart {
	
	//默認:接口中公共靜態常量,公共抽象方法
	void display();
}

b.具體產品角色
 

public class Histogram implements Chart{
	
	public Histogram() {
		System.out.println("創建柱狀圖");
	}

	@Override
	public void display() {
		System.out.println("顯示柱狀圖");
	}

}
public class Pie implements Chart{

	public Pie() {
		System.out.println("初始化餅狀圖");
	}

	@Override
	public void display() {
		System.out.println("顯示餅狀圖");
	}

}

c.工廠類
 

public class FactoryTest {

	public static void main(String[] args) {
		
		Chart chart = ChartFactory.createChart("histogram");
		chart.display();
	}
}

d. 客戶端測試代碼
 

public class FactoryTest {

	public static void main(String[] args) {
	        //如需更換產品,修改參數即可
		Chart chart = ChartFactory.createChart("histogram");
		chart.display();
	}
}


UML類圖:

 缺點:每次更換一個Chart對象的時候,都需要修改客戶端代碼中的靜態工廠方法中的參數,然後將代碼重新編譯運行,這對於客戶端而言,違反了"開閉原則",那什麼方法可以在不修改代碼的前提下,完成產品的更換呢?

方案的改進:
我們可以將靜態工廠方法的參數存儲在XML或者Properties文件中,然後通過工具類獲取

<?xml version="1.0" encoding="UTF-8"?>
<config>
	<chartType>histogram</chartType>
</config>
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLReadUtils {
	//該方法是去 xml中讀取<chartType>標籤中的內容並返回
	
	public static String getChartType() {
		try {
			//創建文檔對象
			DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dFactory.newDocumentBuilder();
			Document doc = builder.parse(new File("ChartConfig.xml"));//是直接在項目工程下的的的
			
			//獲取包含圖表類型的文本節點
			NodeList nl = doc.getElementsByTagName("chartType");
			Node classNode = nl.item(0).getFirstChild();
			String chartType = classNode.getNodeValue().trim();
			return chartType;
		} catch (ParserConfigurationException | SAXException | IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public static void main(String[] args) {
		String chartType = XMLReadUtils.getChartType();
		System.out.println(chartType);
	}
}

經過配置文件優化後的客戶端測試代碼
 

public class FactoryTest {

	public static void main(String[] args) {
		//不再需要通過修改源碼實例想要的產品對象了
		String chartType = XMLReadUtils.getChartType();
		Chart  chart = ChartFactory.createChart(chartType);
		chart.display();
	}
}

優點:
如果需要更換具體圖表對象, 只需修改配置文件config.xml, 無須修改任何源代碼, 符合“開閉原則

1.6 簡單工廠模式的簡化
有時候, 爲了簡化簡單工廠模式, 我們可以將抽象產品類和工廠類合併, 將靜態工廠方法移至抽象產品類中

1.7簡單工廠模式總結
(1)優點:

a.工廠類包含必要的判斷邏輯, 可以決定在什麼時候創建哪一個產品類的實例, 客戶端可以免除直接創建產品對象的職責, 而僅僅“消費”產品, 簡單工廠模式實現了對象創建和使用的分離
b. 客戶端無須知道所創建的具體產品類的類名, 只需要知道具體產品類所對應的參數即可,對於一些複雜的類名, 通過簡單工廠模式可以在一定程度減少使用者的記憶量。
c.通過引入配置文件, 可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。

(2)缺點:

a.由於工廠類集中了所有產品的創建邏輯, 職責過重, 一旦不能正常工作, 整個系統都要受到影響
b.使用簡單工廠模式勢必會增加系統中類的個數( 引入了新的工廠類) , 增加了系統的複雜度和理解難度。
c.系統擴展困難, 一旦添加新產品就不得不修改工廠邏輯, 在產品類型較多時, 有可能造成工廠邏輯過於複雜, 不利於系統的擴展和維護。

(3)適用場景
a.工廠類負責創建的對象比較少, 由於創建的對象較少, 不會造成工廠方法中的業務邏輯太過複雜。
b.客戶端只知道傳入工廠類的參數, 對於如何創建對象並不關心。

JDK使用簡單工廠模式的工具類
DateFormat dateFormat = DateFormat.getDateInstance();
DateFormat dateFormat = DateFormat.getDateInstance(int style);
​​​​​​​DateFormat dateFormat = DateFormat.getDateInstance(int style,Locale aLocale)

參考博文: https://blog.csdn.net/LoveLion/article/details/7862349?utm_source=app

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章