设计模式的征途—2.简单工厂(Simple Factory)模式
工廠模式是最常用的一種創建型模式,通常所說的工廠模式一般是指工廠方法模式。本篇是是工廠方法模式的“小弟”,我們可以將其理解為工廠方法模式的預備知識,它不屬于GoF 23種設計模式,但在軟件開發中卻也應用地比較頻繁。此外,工廠方法模式還有一位“大哥”—抽象工廠模式,會在后面進行介紹。
| 簡單工廠模式(Simple Factory) | 學習難度:★★☆☆☆ | 使用頻率:★★★☆☆ |
一、從一個圖表庫談起
M公司想要基于C#語言開發一套圖表庫,該圖表庫可以為應用系統提供各種不同外觀的圖標,例如柱狀圖、餅狀圖或折線圖等。M公司圖表庫設計開發人員希望為應用系統開發人員提供一套靈活易用的圖表庫,而且可以較為方便地對圖表庫進行擴展,以便于在將來增加一些新類型的圖表。
M公司的程序員提出了一個初始設計方案,將所有圖表的實現代碼封裝在一個Chart類中,其框架代碼如下所示:
public class Chart{private string type; // 圖表類型public Chart(object[][] data, string type){this.type = type;if (this.type.Equals("histogram", StringComparison.OrdinalIgnoreCase)){// 初始化柱狀圖 }else if (this.type.Equals("pie", StringComparison.OrdinalIgnoreCase)){// 初始化餅狀圖 }else if (this.type.Equals("line", StringComparison.OrdinalIgnoreCase)){// 初始化折線圖 }}public void Display(){if (this.type.Equals("histogram", StringComparison.OrdinalIgnoreCase)){// 顯示柱狀圖 }else if (this.type.Equals("pie", StringComparison.OrdinalIgnoreCase)){// 顯示餅狀圖 }else if (this.type.Equals("line", StringComparison.OrdinalIgnoreCase)){// 顯示折線圖 }}}客戶端代碼通過調用Chart類的構造函數來創建圖表對象,根據參數type的不同可以得到不同類型的圖標,然后再調用Display()方法來顯示相應的圖表。
但是,不難看出,Chart類是一個巨大的類,存在很多問題:
- 在Chart類中包含很多if-else代碼塊,相當冗長,可讀性很差;
- Chart類的職責過重,負責初始化和顯示各種圖表對象,違反了單一職責原則;
- 當需要增加新的圖表類型時,必須修改Chart類的源代碼,違反了開閉原則;
- 客戶端只能通過new關鍵字來直接創建Chart對象,Chart類與客戶端類耦合度較高,對象的創建和使用無法分離;
- 客戶端在創建Chart對象之前可能還需要進行大量初始化設置,例如設置柱狀圖的顏色和高度等,如果在Chart類的構造函數中沒有提供一個默認設置,那就只能由客戶端來完成初始設置,這些代碼在每次創建Chart對象時都會出現,導致代碼的重復;
二、簡單工廠模式概述
2.1 要點
簡單工廠模式并不屬于GoF 23種經典設計模式,但通常將它作為學習其他工廠模式的基礎。
簡單工廠(Simple Factory)模式:定義一個工廠類,它可以根據參數的不同返回不同類的實例,被創建的實例通常都具有共同的父類。因為在簡單工廠模式中用于創建實例的方法是靜態(static)方法,因此簡單工廠模式又被稱為靜態工廠方法模式,它屬于創建型模式。
簡單工廠模式的要點在于:當你需要什么,只需要傳入一個正確的參數,就可以獲取你所需的對象,而無須知道其創建細節。
2.2 結構圖
簡單工廠模式包含3個角色:
- Factory - 工廠角色:該模式的核心,負責實現創建所有產品實例的內部邏輯,提供一個靜態的工廠方法GetProduct(),返回抽象產品類型Product的實例。
- Product - 抽象產品角色:所有產品類的父類,封裝了各種產品對象的共有方法,它的引入將提高系統的靈活性,使得在工廠類中只需要定義一個通用的工廠方法,因為所有創建的具體產品對象都是其子類對象。
- ConcreteProduct - 具體產品角色:簡單工廠模式的創建目標,所有被創建的對象都充當這個角色的某個具體類的實例。
在簡單工廠模式中,客戶端通過工廠類來創建一個產品類的實例,而無須直接使用new關鍵字來創建對象。(可以看出,它是工廠模式家族中最簡單的一員)
三、重構圖表庫的實現
3.1 新的結構圖
為了將Chart類的職責分離,同時將Chart對象的創建和使用分離,M公司開發人員決定使用簡單工廠模式對圖表庫進行重構,重構后的結構圖如下所示:
3.2 新的代碼實現
(1)抽象產品角色:IChartable接口
public interface IChartable{void Display();}(2)具體產品角色:各種圖表類型
public class HistogramChart : IChartable{public HistogramChart(){Console.WriteLine("創建柱狀圖...");}public void Display(){Console.WriteLine("顯示柱狀圖...");}}public class LineChart : IChartable{public LineChart(){Console.WriteLine("創建折線圖...");}public void Display(){Console.WriteLine("顯示折線圖...");}}public class PieChart : IChartable{public PieChart(){Console.WriteLine("創建餅狀圖...");}public void Display(){Console.WriteLine("顯示餅狀圖...");}}(3)工廠角色:ChartFactory
public class ChartFactory{public static IChartable GetChart(string type){IChartable chart = null;if (type.Equals("histogram", StringComparison.OrdinalIgnoreCase)){chart = new HistogramChart();Console.WriteLine("初始化設置柱狀圖...");}else if (type.Equals("pie", StringComparison.OrdinalIgnoreCase)){chart = new PieChart();Console.WriteLine("初始化設置餅狀圖...");}else if (type.Equals("line", StringComparison.OrdinalIgnoreCase)){chart = new PieChart();Console.WriteLine("初始化設置折線圖...");}return chart;}}(4)客戶端調用:
public static void Main(){IChartable chart = ChartFactory.GetChart("histogram");if (chart != null){chart.Display();}chart = ChartFactory.GetChart("pie");if (chart != null){chart.Display();}}運行結果如下:
在客戶端代碼中,使用工廠類的靜態方法來創建具體產品對象,如果需要更換產品,只需要修改靜態工廠方法中的參數即可。例如:將柱狀圖改為餅狀圖,只需要將代碼:
IChartable chart = ChartFactory.GetChart("histogram");改為:
IChartable chart = ChartFactory.GetChart("pie");3.3 改進的方案
M公司開發人員發現在創建具體Chart對象時,每次更換一個Chart對象都需要修改客戶端中靜態工廠方法的參數,客戶端代碼需要重新編譯,這對于客戶端而言,是違反了開閉原則的。于是,開發人員希望有一種方法能夠在不修改客戶端代碼地前提下更換具體產品對象。
因此,他們考慮使用配置文件(XML)來實現:
<?xml version="1.0" encoding="utf-8" ?> <configuration><appSettings><add key="charttype" value="histogram"/></appSettings> </configuration>客戶端因此改為:
public static void Main(){string type = AppConfigHelper.GetChartType(); // 讀取配置文件中的charttypeif (string.IsNullOrEmpty(type)){return;}IChartable chart = ChartFactory.GetChart(type);if (chart != null){chart.Display();}}運行結果如下:
四、簡單工廠模式總結
4.1 主要優點
- 實現了對象創建和使用的分離:客戶端可以免除直接創建產品對象的職責,而僅僅“消費”產品。
- 客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的的參數即可。
- 通過引入配置文件,可以在不修改任何客戶端代碼地情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
4.2 主要缺點
- 由于工廠類集中了所有產品的創建邏輯,職責過重,一旦不能正常工作,整個系統都要受影響。
- 使用簡單工廠模式勢必會增加系統中類的個數(引入新的工廠類),增加了系統的復雜度和理解難度。
- 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能會造成工廠邏輯過于復雜,不利于系統的擴展和維護。
- 簡單工廠模式由于使用了靜態工廠方法,造成工廠角色無法形成基于繼承的等級結構。
4.3 適用場景
- 工廠類負責創建的對象比較少,由于創建的對象較少,不會造成工廠方法中的業務邏輯太過復雜。
- 客戶端只需要知道傳入工廠類的參數,對于如何創建對象并不關心。
參考資料
? ? ??
劉偉,《設計模式的藝術—軟件開發人員內功修煉之道》
?
作者:周旭龍
出處:http://edisonchou.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
總結
以上是生活随笔為你收集整理的设计模式的征途—2.简单工厂(Simple Factory)模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STL - Unorderedset -
- 下一篇: wpsofficeapp的excel表格