設計模式的征途—2.簡單工廠(Simple Factory)模式

  工廠模式是最經常使用的一種建立型模式,一般所說的工廠模式通常是指工廠方法模式。本篇是是工廠方法模式的「小弟」,咱們能夠將其理解爲工廠方法模式的預備知識,它不屬於GoF 23種設計模式,但在軟件開發中卻也應用地比較頻繁。此外,工廠方法模式還有一位「大哥」—抽象工廠模式,會在後面進行介紹。程序員

簡單工廠模式(Simple Factory) 學習難度:★★☆☆☆ 使用頻率:★★★☆☆

1、從一個圖表庫談起

  M公司想要基於C#語言開發一套圖表庫,該圖表庫能夠爲應用系統提供各類不一樣外觀的圖標,例如柱狀圖、餅狀圖或折線圖等。M公司圖表庫設計開發人員但願爲應用系統開發人員提供一套靈活易用的圖表庫,並且能夠較爲方便地對圖表庫進行擴展,以便於在未來增長一些新類型的圖表。設計模式

  M公司的程序員提出了一個初始設計方案,將全部圖表的實現代碼封裝在一個Chart類中,其框架代碼以下所示:app

    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、簡單工廠模式概述

2.1 要點

  簡單工廠模式並不屬於GoF 23種經典設計模式,但一般將它做爲學習其餘工廠模式的基礎。學習

簡單工廠(Simple Factory)模式:定義一個工廠類,它能夠根據參數的不一樣返回不一樣類的實例,被建立的實例一般都具備共同的父類。由於在簡單工廠模式中用於建立實例的方法是靜態(static)方法,所以簡單工廠模式又被稱爲靜態工廠方法模式,它屬於建立型模式。this

  簡單工廠模式的要點在於:當你須要什麼,只須要傳入一個正確的參數,就能夠獲取你所需的對象,而無須知道其建立細節spa

2.2 結構圖

  簡單工廠模式包含3個角色:設計

  • Factory - 工廠角色:該模式的核心,負責實現建立全部產品實例的內部邏輯,提供一個靜態的工廠方法GetProduct(),返回抽象產品類型Product的實例。
  • Product - 抽象產品角色:全部產品類的父類,封裝了各類產品對象的共有方法,它的引入將提升系統的靈活性,使得在工廠類中只須要定義一個通用的工廠方法,由於全部建立的具體產品對象都是其子類對象。
  • ConcreteProduct - 具體產品角色:簡單工廠模式的建立目標,全部被建立的對象都充當這個角色的某個具體類的實例。

  在簡單工廠模式中,客戶端經過工廠類來建立一個產品類的實例,而無須直接使用new關鍵字來建立對象。(能夠看出,它是工廠模式家族中最簡單的一員)code

3、重構圖表庫的實現

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(); // 讀取配置文件中的charttype
        if (string.IsNullOrEmpty(type))
        {
            return;
        }

        IChartable chart = ChartFactory.GetChart(type);
        if (chart != null)
        {
            chart.Display();
        }
    }

  運行結果以下:

  

4、簡單工廠模式總結

4.1 主要優勢

  • 實現了對象建立和使用的分離:客戶端能夠免除直接建立產品對象的職責,而僅僅「消費」產品。
  • 客戶端無須知道所建立的具體產品類的類名,只須要知道具體產品類所對應的的參數便可。
  • 經過引入配置文件,能夠在不修改任何客戶端代碼地狀況下更換和增長新的具體產品類,在必定程度上提升了系統的靈活性。

4.2 主要缺點

  • 因爲工廠類集中了全部產品的建立邏輯,職責太重,一旦不能正常工做,整個系統都要受影響。
  • 使用簡單工廠模式勢必會增長系統中類的個數(引入新的工廠類),增長了系統的複雜度和理解難度。
  • 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能會形成工廠邏輯過於複雜,不利於系統的擴展和維護。
  • 簡單工廠模式因爲使用了靜態工廠方法,形成工廠角色沒法造成基於繼承的等級結構。

4.3 適用場景

  • 工廠類負責建立的對象比較少,因爲建立的對象較少,不會形成工廠方法中的業務邏輯太過複雜。
  • 客戶端只須要知道傳入工廠類的參數,對於如何建立對象並不關心。

參考資料

      DesignPattern

  劉偉,《設計模式的藝術—軟件開發人員內功修煉之道》

 

相關文章
相關標籤/搜索