詳解設計模式之工廠模式(簡單工廠+工廠方法+抽象工廠)

園子裏關於23種設計模式的博文已經能夠說是成千上萬、車載斗量、屯街塞巷、不可勝數、數不勝數、摩肩接踵、汗牛充棟、車水馬龍、門庭若市、琳琅滿目直至讓人眼花繚亂了。在這樣的大環境下之因此來寫設計模式類的博文,並非像一些"非主流"的愛情觀那樣"寧缺毋濫"。 只是其一呢,由於至關於給本身作一個總結,加深一下本身這方面的認識,由於掌握了和把它寫出來我感受後者還能夠對技能有一個提高,其二呢是由於最近公司有一個內部的training須要講設計模式。html

C# 設計模式
v寫在前面
在這裏呢,須要向園子裏全部寫過設計模式的前輩們和程傑老師致敬,在coding的道路上從當初剛畢業的懵懵懂懂到如今的XXXXX,一路上是大家給了咱們coding啓迪。不矯情了,開始正事。(建議在正式認識設計模式以前,能夠先參照個人 上一篇博文學習一下設計模式的六大原則。)
v簡單工廠模式

1.介紹: sql

簡單工廠模式是屬於建立型模式,又叫作靜態工廠方法(Static Factory Method)模式,但不屬於23種GOF設計模式之一。簡單工廠模式是由一個工廠對象決定建立出哪種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,能夠理解爲是不一樣工廠模式的一個特殊實現。

2.延伸: 數據庫

試想一下,當咱們在coding的時候,在A類裏面只要NEW了一個B類的對象,那麼A類就會從某種程度上依賴B類。若是在後期需求發生變化或者是維護的時候,須要修改B類的時候,咱們就須要打開源代碼修改全部與這個類有關的類了,作太重構的朋友都知道,這樣的事情雖然沒法徹底避免,但確實是一件讓人心碎的事情。

3.模擬場景: windows

歐美主導的以賽車爲主題的系列電影《速度與激情》系列相信你們都看過,裏面的男主角(zhǔ jué,加個拼音,常常聽到有人說什麼主腳主腳的,雖然以前我也不肯定是zhǔ jué仍是主腳,可是我沒念過主腳,我在不肯定的狀況下我都是念男一號)範·迪塞爾在每一集裏面作不一樣的事情都是開不一樣的車子,相信你們都以爲很酷吧。設計模式

C# 抽象工廠設計模式

人家酷也沒辦法,誰叫人家是大佬呢。這裏咱們試想一下,若是這是一套程序,咱們該怎麼設計?每次不一樣的畫面或者劇情範·迪塞爾都須要按照導演的安排開不同的車,去參加賽車須要開的是跑車,可能導演就會說下一場戲:範·迪塞爾下一場戲須要開跑車(參數),要去參加五環首屆跑車拉力賽,這時候場務(工廠類)接到導演的命令(跑車參數)後須要從車庫開出一輛跑車(具體產品)交到範·迪塞爾手上讓他去準備五環首屆跑車拉力賽。這套程序的整個生命週期就算完成了。(什麼?沒完成?難不成你還真想來個五環首屆跑車拉力賽了啊:)架構

根據導演不一樣的指令,開的車是不同的,可是車都是在車庫中存在的。車都屬於同一種抽象,車庫裏全部的車都有本身的特徵,這些特徵就是條件。導演發出指令的時候,只要告訴場務特徵,場務就知道提什麼車。這就簡單工廠模式的典型案例。oracle

4.簡單工廠UML類圖: (UML圖是我用windows自帶的paint手工畫的,因此可能不是很專業)app

C# 簡單工廠模式

5.代碼演示: 框架

抽象產品類代碼: ide

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 抽象產品類: 汽車
    /// </summary>
    public interface ICar
    {
        void GetCar();
    }
}

具體產品類代碼: 

namespace CNBlogs.DesignPattern.Common
{
    public enum CarType
    {
        SportCarType = 0,
        JeepCarType = 1,
        HatchbackCarType = 2
    }

    /// <summary>
    /// 具體產品類: 跑車
    /// </summary>
    public class SportCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("場務把跑車交給範·迪塞爾");
        }
    }

    /// <summary>
    /// 具體產品類: 越野車
    /// </summary>
    public class JeepCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("場務把越野車交給範·迪塞爾");
        }
    }

    /// <summary>
    /// 具體產品類: 兩箱車
    /// </summary>
    public class HatchbackCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("場務把兩箱車交給範·迪塞爾");
        }
    }
}

簡單工廠核心代碼: 

namespace CNBlogs.DesignPattern.Common
{
    public class Factory
    {
        public ICar GetCar(CarType carType)
        {
            switch (carType)
            {
                case CarType.SportCarType:
                    return new SportCar();
                case CarType.JeepCarType:
                    return new JeepCar();
                case CarType.HatchbackCarType:
                    return new HatchbackCar();
                default:
                    throw new Exception("愛上一匹野馬,可個人家裏沒有草原. 你走吧!");
            }
        }
    }
}

客戶端調用代碼: 

//------------------------------------------------------------------------------
// <copyright file="Program.cs" company="CNBlogs Corporation">
//     Copyright (C) 2015-2016 All Rights Reserved
//     原博文地址: http://www.cnblogs.com/toutou/
//     做      者: 請叫我頭頭哥
// </copyright> 
//------------------------------------------------------------------------------
namespace CNBlogs.DesignPattern
{
    using System;
    using CNBlogs.DesignPattern.Common;

    class Program
    {
        static void Main(string[] args)
        {
            ICar car;
            try
            {
                Factory factory = new Factory();

                Console.WriteLine("範·迪塞爾下一場戲開跑車。");
                car = factory.GetCar(CarType.SportCarType);
                car.GetCar();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

簡單工廠的簡單案例就這麼多,真正在項目實戰的話可能還有須要改進和擴展的地方。因需求而定吧。

6.簡單工廠的優勢/缺點: 

  • 優勢:簡單工廠模式可以根據外界給定的信息,決定究竟應該建立哪一個具體類的對象。明確區分了各自的職責和權力,有利於整個軟件體系結構的優化。
  • 缺點:很明顯工廠類集中了全部實例的建立邏輯,容易違反GRASPR的高內聚的責任分配原則
v工廠方法模式

1.介紹: 

工廠方法模式Factory Method,又稱多態性工廠模式。在工廠方法模式中,核心的工廠類再也不負責全部的產品的建立,而是將具體建立的工做交給子類去作。該核心類成爲一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪個產品類應當被實例化這種細節。

2.定義: 

工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。首先徹底實現‘開-閉 原則’,實現了可擴展。其次更復雜的層次結構,能夠應用於產品結果複雜的場合。

3.延伸: 

在上面簡單工廠的引入中,咱們將實例化具體對象的工做所有交給了專門負責建立對象的工廠類(場務)中,這樣就能夠在咱們獲得導演的命令後建立對應的車(產品)類了。可是劇組的導演是性情比較古怪的,可能指令也是無限變化的。這樣就有了新的問題,一旦導演發出的指令時咱們沒有預料到的,就必須得修改源代碼。這也不是很合理的。工廠方法就是爲了解決這類問題的。

4.模擬場景: 

仍是上面範·迪塞爾要去參加五環首屆跑車拉力賽的場景。由於要拍攝《速度與激情8》,導演組車的種類增多了,陣容也更加豪華了,加上導演古怪的性格可能每一場戲絕對須要試駕幾十種車。若是車庫沒有的車(具體產品類)能夠由場務(具體工廠類)直接去4S店取,這樣沒增長一種車(具體產品類)就要對應的有一個場務(具體工廠類),他們互相之間有着各自的職責,互不影響,這樣可擴展性就變強了。

5.工廠方法UML類圖: (UML圖是我用windows自帶的paint手工畫的,因此可能不是很專業

C# 工廠方法模式

6.代碼演示: 

抽象工廠代碼: 

namespace CNBlogs.DesignPattern.Common
{
    public interface IFactory
    {
        ICar CreateCar();
    }
}

抽象產品代碼: 

namespace CNBlogs.DesignPattern.Common
{
    public interface ICar
    {
        void GetCar();
    }
}

具體工廠代碼: 

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    ///  具體工廠類: 用於建立跑車類
    /// </summary>
    public class SportFactory : IFactory
    {
        public ICar CreateCar()
        {
            return new SportCar();
        }
    }

    /// <summary>
    ///  具體工廠類: 用於建立越野車類
    /// </summary>
    public class JeepFactory : IFactory
    {
        public ICar CreateCar()
        {
            return new JeepCar();
        }
    }

    /// <summary>
    ///  具體工廠類: 用於建立兩廂車類
    /// </summary>
    public class HatchbackFactory : IFactory
    {
        public ICar CreateCar()
        {
            return new HatchbackCar();
        }
    }
}

具體產品代碼: 

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 具體產品類: 跑車
    /// </summary>
    public class SportCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("場務把跑車交給範·迪塞爾");
        }
    }

    /// <summary>
    /// 具體產品類: 越野車
    /// </summary>
    public class JeepCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("場務把越野車交給範·迪塞爾");
        }
    }

    /// <summary>
    /// 具體產品類: 兩箱車
    /// </summary>
    public class HatchbackCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("場務把兩箱車交給範·迪塞爾");
        }
    }
}

客戶端代碼: 

//------------------------------------------------------------------------------
// <copyright file="Program.cs" company="CNBlogs Corporation">
//     Copyright (C) 2015-2016 All Rights Reserved
//     原博文地址: http://www.cnblogs.com/toutou/
//     做      者: 請叫我頭頭哥
// </copyright> 
//------------------------------------------------------------------------------
namespace CNBlogs.DesignPattern
{
    using System.IO;
    using System.Configuration;
    using System.Reflection;
    using CNBlogs.DesignPattern.Common;

    class Program
    {
        static void Main(string[] args)
        {
            // 工廠類的類名寫在配置文件中能夠方便之後修改
            string factoryType = ConfigurationManager.AppSettings["FactoryType"];

            // 這裏把DLL配置在數據庫是由於之後數據可能發生改變
            // 好比說如今的數據是從sql server取的,之後須要從oracle取的話只須要添加一個訪問oracle數據庫的工程就好了
            string dllName = ConfigurationManager.AppSettings["DllName"];

            // 利用.NET提供的反射能夠根據類名來建立它的實例,很是方便
            var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            string codeBase = currentAssembly.CodeBase.ToLower().Replace(currentAssembly.ManifestModule.Name.ToLower(), string.Empty);
            IFactory factory = Assembly.LoadFrom(Path.Combine(codeBase, dllName)).CreateInstance(factoryType) as IFactory;
            ICar car = factory.CreateCar();
            car.GetCar();
        }
    }
}

7.工廠方法的優勢/缺點: 

  • 優勢:
    • 子類提供掛鉤。基類爲工廠方法提供缺省實現,子類能夠重寫新的實現,也能夠繼承父類的實現。-- 加一層間接性,增長了靈活性
    • 屏蔽產品類。產品類的實現如何變化,調用者都不須要關心,只需關心產品的接口,只要接口保持不變,系統中的上層模塊就不會發生變化。
    • 典型的解耦框架。高層模塊只須要知道產品的抽象類,其餘的實現類都不須要關心,符合迪米特法則,符合依賴倒置原則,符合里氏替換原則。
    • 多態性:客戶代碼能夠作到與特定應用無關,適用於任何實體類。
  • 缺點:須要Creator和相應的子類做爲factory method的載體,若是應用模型確實須要creator和子類存在,則很好;不然的話,須要增長一個類層次。(不過說這個缺點好像有點吹毛求疵了)
v抽象工廠模式

1.介紹: 

抽象工廠模式是全部形態的工廠模式中最爲抽象和最具通常性的一種形態。抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式能夠向客戶端提供一個接口,使客戶端在沒必要指定產品的具體的狀況下,建立多個產品族中的產品對象。根據里氏替換原則,任何接受父類型的地方,都應當可以接受子類型。所以,實際上系統所須要的,僅僅是類型與這些抽象產品角色相同的一些實例,而不是這些抽象產品的實例。換言之,也就是這些抽象產品的具體子類的實例。工廠類負責建立抽象產品的具體子類的實例。

2.定義: 

爲建立一組相關或相互依賴的對象提供一個接口,並且無需指定他們的具體類。

3.模擬場景: 

咱們仍是繼續範·迪塞爾的例子,每每這些大牌生活中常常參加一些活動,或是商務活動或是公益活動。無論參加什麼活動,加上老範(範·迪塞爾名字太長,如下文中簡稱老範)的知名度,他的車確定很多,可能光跑車或者光越野車就有多輛。好比說有跑車(多輛,跑車系列的具體產品)、越野車(多輛,越野車系列的具體產品)、兩箱車(多輛,兩箱車系列的具體產品)。可能不少大牌明星都是如此的。假設老範家裏,某一個車庫(具體工廠)只存放某一系列的車(好比說跑車車庫只存放跑車一系列具體的產品),每次要某一輛跑車的時候確定要從這個跑車車庫裏開出來。用了OO(Object Oriented,面向對象)的思想去理解,全部的車庫(具體工廠)都是車庫類(抽象工廠)的某一個,而每一輛車又包括具體的開車時候所背的包(某一具體產品。包是也是放在車庫裏的,不一樣的車搭配不一樣的包,咱們把車和車對應的揹包稱做出去參加活動的裝備),這些具體的包其實也都是揹包(抽象產品),具體的車其實也都是車(另外一個抽象產品)。

4.場景分析: 

上面的場景可能有點稀裏糊塗的,可是用OO的思想結合前面的簡單工廠和工廠方法的思路去理解的話,也好理解。

下面讓咱們來捋一捋這個思路:

  • 抽象工廠:虛擬的車庫,只是全部車庫的一個概念。在程序中多是一個藉口或者抽象類,對其餘車庫的規範,開車和取包。
  • 具體工廠:具體存在的車庫,用來存放車和車對應的揹包。在程序中繼承抽象工廠,實現抽象工廠中的方法,能夠有具體的產品。
  • 抽象產品:虛擬的裝備(車和對應的揹包),也只是全部裝備的一個概念。在程序中多是多個接口或者多個抽象類,對具體的裝備起到規範。
  • 具體產品:活動參加的具體裝備,它指的是組成裝備的某一輛車或者揹包。它繼承自某一個抽象產品。

5.抽象工廠UML類圖: (UML圖是我用windows自帶的paint手工畫的,因此可能不是很專業)

6.代碼演示: 

抽象工廠代碼: 

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 抽象工廠類
    /// </summary>
    public abstract class AbstractEquipment
    {
        /// <summary>
        /// 抽象方法: 建立一輛車
        /// </summary>
        /// <returns></returns>
        public abstract AbstractCar CreateCar();

        /// <summary>
        /// 抽象方法: 建立揹包
        /// </summary>
        /// <returns></returns>
        public abstract AbstractBackpack CreateBackpack();
    }
}

抽象產品代碼: 

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 抽象產品: 車抽象類
    /// </summary>
    public abstract class AbstractCar
    {
        /// <summary>
        /// 車的類型屬性
        /// </summary>
        public abstract string Type
        {
            get;
        }

        /// <summary>
        /// 車的顏色屬性
        /// </summary>
        public abstract string Color
        {
            get;
        }
    }

    /// <summary>
    /// 抽象產品: 揹包抽象類
    /// </summary>
    public abstract class AbstractBackpack
    {
        /// <summary>
        /// 包的類型屬性
        /// </summary>
        public abstract string Type
        {
            get;
        }

        /// <summary>
        /// 包的顏色屬性
        /// </summary>
        public abstract string Color
        {
            get;
        }
    }
}

具體工廠代碼: 

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 運動裝備
    /// </summary>
    public class SportEquipment : AbstractEquipment
    {
        public override AbstractCar CreateCar()
        {
            return new SportCar();
        }

        public override AbstractBackpack CreateBackpack()
        {
            return new SportBackpack();
        }
    }

    /// <summary>
    /// 越野裝備  這裏就不添加了,同運動裝備一個原理,demo裏只演示一個,實際項目中能夠按需添加
    /// </summary>
    //public class JeepEquipment : AbstractEquipment
    //{
    //    public override AbstractCar CreateCar()
    //    {
    //        return new JeeptCar();
    //    }

    //    public override AbstractBackpack CreateBackpack()
    //    {
    //        return new JeepBackpack();
    //    }
    //}
}

具體產品代碼: 

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 跑車
    /// </summary>
    public class SportCar : AbstractCar
    {
        private string type = "Sport";
        private string color = "Red";

        /// <summary>
        /// 重寫基類的Type屬性
        /// </summary>
        public override string Type
        {
            get
            {
                return type;
            }
        }

        /// <summary>
        /// 重寫基類的Color屬性
        /// </summary>
        public override string Color
        {
            get
            {
                return color;
            }
        }
    }

    /// <summary>
    /// 運動揹包
    /// </summary>
    public class SportBackpack : AbstractBackpack
    {
        private string type = "Sport";
        private string color = "Red";

        /// <summary>
        /// 重寫基類的Type屬性
        /// </summary>
        public override string Type
        {
            get
            {
                return type;
            }
        }

        /// <summary>
        /// 重寫基類的Color屬性
        /// </summary>
        public override string Color
        {
            get
            {
                return color;
            }
        }
    }
}
//具體產品能夠有不少不少, 至於越野類的具體產品這裏就不列出來了。

建立裝備代碼: 

namespace CNBlogs.DesignPattern.Common
{
    public class CreateEquipment
    {
        private AbstractCar fanCar;
        private AbstractBackpack fanBackpack;
        public CreateEquipment(AbstractEquipment equipment)
        {
            fanCar = equipment.CreateCar();
            fanBackpack = equipment.CreateBackpack();
        }

        public void ReadyEquipment()
        {
            Console.WriteLine(string.Format("老範揹着{0}色{1}包開着{2}色{3}車。", 
                fanBackpack.Color, 
                fanBackpack.Type,
                fanCar.Color,
                fanCar.Type
                ));
        }
    }
}

客戶端代碼: 

//------------------------------------------------------------------------------
// <copyright file="Program.cs" company="CNBlogs Corporation">
//     Copyright (C) 2015-2016 All Rights Reserved
//     原博文地址: http://www.cnblogs.com/toutou/
//     做      者: 請叫我頭頭哥
// </copyright> 
//------------------------------------------------------------------------------
namespace CNBlogs.DesignPattern
{
    using System;
    using System.Configuration;
    using System.Reflection;

    using CNBlogs.DesignPattern.Common;

    class Program
    {
        static void Main(string[] args)
        {
            // ***具體app.config配置以下*** //
            //<add key="assemblyName" value="CNBlogs.DesignPattern.Common"/>
            //<add key="nameSpaceName" value="CNBlogs.DesignPattern.Common"/>
            //<add key="typename" value="SportEquipment"/>
            // 建立一個工廠類的實例
            string assemblyName = ConfigurationManager.AppSettings["assemblyName"];
            string fullTypeName = string.Concat(ConfigurationManager.AppSettings["nameSpaceName"], ".", ConfigurationManager.AppSettings["typename"]);
            AbstractEquipment factory = (AbstractEquipment)Assembly.Load(assemblyName).CreateInstance(fullTypeName);
            CreateEquipment equipment = new CreateEquipment(factory);
            equipment.ReadyEquipment();
            Console.Read();
        }
    }
}

抽象工廠模式符合了六大原則中的開閉原則、里氏代換原則、依賴倒轉原則等等

7.抽象工廠的優勢/缺點: 

  • 優勢:
    • 抽象工廠模式隔離了具體類的生產,使得客戶並不須要知道什麼被建立。
    • 當一個產品族中的多個對象被設計成一塊兒工做時,它能保證客戶端始終只使用同一個產品族中的對象。
    • 增長新的具體工廠和產品族很方便,無須修改已有系統,符合「開閉原則」。
  • 缺點:增長新的產品等級結構很複雜,須要修改抽象工廠和全部的具體工廠類,對「開閉原則」的支持呈現傾斜性。(不過說這個缺點好像有點吹毛求疵了)
v博客總結

這篇博文從晚上下班7點到家一直寫到如今,說了一夜的工廠,也扯了一夜的速度與激情,在本博文完結的最後,給你們來一張速度與激情的畫面精彩照。(ps:是否是以爲這種畫面再配上一曲DJ一瓶啤酒會更嗨啊?哈哈...)

咱們使用設計模式目的無非只有三個:a)縮短開發時間;b)下降維護成本;c)在應用程序之間和內部輕鬆集成。具體何時使用何種設計模式還得因項目而異。之因此對設計模式舊調重彈只是但願這個博文能對本身的架構之路有所提高,同時若是能幫助到其餘人那就更完美了。

 


做  者:請叫我頭頭哥
出  處:http://www.cnblogs.com/toutou/
關於做者:專一於基礎平臺的項目開發。若有問題或建議,請多多賜教!
版權聲明:本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
特此聲明:全部評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:若是您以爲文章對您有幫助,能夠點擊文章右下角推薦一下。您的鼓勵是做者堅持原創和持續寫做的最大動力!

相關文章
相關標籤/搜索