C#設計模式學習筆記:(2)工廠方法模式

来源:https://www.cnblogs.com/atomy/archive/2020/01/09/12170509.html
-Advertisement-
Play Games

本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7567880.html,記錄一下學習過程以備後續查用。 一、引言 接上一篇C#設計模式學習筆記:簡單工廠模式(工廠方法模式前奏篇),通過簡單工廠模式的瞭解,它的缺點就是隨著需求的變化我們要不停地修改工廠里 面的 ...


    本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7567880.html,記錄一下學習過程以備後續查用。

    一、引言

    接上一篇C#設計模式學習筆記:簡單工廠模式(工廠方法模式前奏篇),通過簡單工廠模式的瞭解,它的缺點就是隨著需求的變化我們要不停地修改工廠里

面的方法的代碼,需求變化越多,裡面的if--else也越多,這樣就會造成簡單工廠的實現邏輯過於複雜。

    依設計原則里的開閉原則--對增加代碼開放,對修改代碼關閉,我們不能總是這樣修改簡單工廠裡面的方法。

    下麵看看工廠方法模式是如何解決該問題的?

    二、工廠方法模式介紹

   工廠方法模式:英文名稱--Factory Method Pattern;分類--創建型。

    2.1、動機(Motivate)

    在軟體系統的構建過程中,經常面臨著“某個對象”的創建工作:由於需求的變化,這個對象(的具體實現)經常面臨著劇烈的變化,但是它卻擁有比

較穩定的介面。

    如何應對這種變化?如何提供一種“封裝機制”來隔離出“這個易變對象”的變化,從而保持系統中“其他依賴對象的對象”不隨著需求改變而改變?

    2.2、意圖(Intent)

    定義一個用於創建對象的介面,讓子類決定實例化哪一個類。Factory Method使得一個類的實例化延遲到子類。--《設計模式》GoF

    2.3、結構圖(Structure)

    2.4、模式的組成

    從上圖可以看出,在工廠方法模式的結構圖有以下角色:

    1)抽象工廠角色(Creator):充當抽象工廠角色,定義工廠類所具有的基本的操作,任何具體工廠都必須繼承該抽象類。

    2)具體工廠角色(ConcreteCreator):充當具體工廠角色,該類必須繼承抽象工廠角色,實現抽象工廠定義的方法,用來創建具體產品。

    3)抽象產品角色(Product):充當抽象產品角色,定義了產品類型所有具有的基本操作,具體產品必須繼承該抽象類。

    4)具體產品角色(ConcreteProduct):充當具體產品角色,實現抽象產品類對定義的抽象方法,由具體工廠類創建,它們之間有一一對應的關係。

    2.5、工廠方法模式代碼實現

    面向對象設計三大原則:

    1)哪裡有變化就封裝哪裡。

    2)面向抽象編程,細節和高層實現都要依賴抽象。

    3)多組合,少繼承。

    這三大原則是最根本的原則,學習設計模式必須以這三個原則為基點,否則都是枉然。根據這三大原則又衍生出來6個具體的原則,分別是單一職責

原則、開閉原則、里氏替換原則、依賴倒置原則、介面隔離原則、迪米特法則。

    既然工廠類有變化,我們就封裝它,面向抽象編程。我們先抽象出一個工廠基類,然後每個需求都實現一個具體的工廠類,這樣我們就符合了開閉原

,讓一個工廠生產一款產品,並一一對應。具體產品的創建推遲到子類中,此時工廠類(基類)不再負責所有產品的創建,而只是給出具體工廠必須

實現的介面,這樣工廠方法模式就可以允許系統不修改工廠類邏輯的情況下來添加新產品,也就剋服了簡單工廠模式中缺點。

    下麵是工廠方法模式的實現代碼:

    class Program
    {
        /// <summary>
        /// 汽車抽象類
        /// </summary>
        public abstract class Car
        {
            //開始行駛
            public abstract void Go();
        }

        /// <summary>
        /// 紅旗汽車
        /// </summary>
        public class HongQiCar : Car
        {
            public override void Go()
            {
                Console.WriteLine("紅旗汽車生產中。");
            }
        }

        /// <summary>
        /// 奧迪汽車
        /// </summary>
        public class AoDiCar : Car
        {
            public override void Go()
            {
                Console.WriteLine("奧迪汽車生產中。");
            }
        }

        /// <summary>
        /// 抽象工廠類
        /// </summary>
        public abstract class Factory
        {
            //工廠方法
            public abstract Car CreateCar();
        }

        /// <summary>
        /// 紅旗汽車工廠類
        /// </summary>
        public class HongQiCarFactory : Factory
        {
            /// <summary>
            /// 負責生產紅旗汽車
            /// </summary>
            /// <returns></returns>
            public override Car CreateCar()
            {
                return new HongQiCar();
            }
        }

        /// <summary>
        /// 奧迪汽車工廠類
        /// </summary>
        public class AoDiCarFactory : Factory
        {
            /// <summary>
            /// 負責創建奧迪汽車
            /// </summary>
            /// <returns></returns>
            public override Car CreateCar()
            {
                return new AoDiCar();
            }
        }

        static void Main(string[] args)
        {
            #region 工廠方法模式
            //初始化創建汽車的兩個工廠
            Factory hongQiCarFactory = new HongQiCarFactory();
            Factory aoDiCarFactory = new AoDiCarFactory();

            //生產一輛紅旗汽車
            Car hongQi = hongQiCarFactory.CreateCar();
            hongQi.Go();

            //生產一輛奧迪汽車
            Car aoDi = aoDiCarFactory.CreateCar();
            aoDi.Go();

            Console.Read();
            #endregion
        }
    }
View Code

    運行結果如下:

    使用工廠方法實現的系統,如果系統需要添加新產品時,我們可以利用多態性來完成系統的擴展,對於抽象工廠類和具體工廠中的代碼都不需要做任

何改動。假如我們想生產賓士車,我們只需從Car抽象類下繼承一個BenChiCar類、在Factory抽象類下繼承一個“賓士”的工廠類BenChiCarFactory就可

以實現了:

    class Program
    {
        /// <summary>
        /// 汽車抽象類
        /// </summary>
        public abstract class Car
        {
            //開始行駛
            public abstract void Go();
        }

        /// <summary>
        /// 紅旗汽車
        /// </summary>
        public class HongQiCar : Car
        {
            public override void Go()
            {
                Console.WriteLine("紅旗汽車生產中。");
            }
        }

        /// <summary>
        /// 奧迪汽車
        /// </summary>
        public class AoDiCar : Car
        {
            public override void Go()
            {
                Console.WriteLine("奧迪汽車生產中。");
            }
        }

        /// <summary>
        /// 賓士汽車
        /// </summary>
        public class BenChiCar : Car
        {
            public override void Go()
            {
                Console.WriteLine("賓士汽車生產中。");
            }
        }

        /// <summary>
        /// 抽象工廠類
        /// </summary>
        public abstract class Factory
        {
            //工廠方法
            public abstract Car CreateCar();
        }

        /// <summary>
        /// 紅旗汽車工廠類
        /// </summary>
        public class HongQiCarFactory : Factory
        {
            /// <summary>
            /// 負責生產紅旗汽車
            /// </summary>
            /// <returns></returns>
            public override Car CreateCar()
            {
                return new HongQiCar();
            }
        }

        /// <summary>
        /// 奧迪汽車工廠類
        /// </summary>
        public class AoDiCarFactory : Factory
        {
            /// <summary>
            /// 負責創建奧迪汽車
            /// </summary>
            /// <returns></returns>
            public override Car CreateCar()
            {
                return new AoDiCar();
            }
        }

        /// <summary>
        /// 賓士汽車工廠類
        /// </summary>
        public class BenChiCarFactory : Factory
        {
            /// <summary>
            /// 負責生產賓士汽車
            /// </summary>
            /// <returns></returns>
            public override Car CreateCar()
            {
                return new BenChiCar();
            }
        }

        static void Main(string[] args)
        {
            #region 工廠方法模式
            //初始化創建汽車的兩個工廠
            Factory hongQiCarFactory = new HongQiCarFactory();
            Factory aoDiCarFactory = new AoDiCarFactory();
            Factory benChiCarFactory = new BenChiCarFactory();

            //生產一輛紅旗汽車
            Car hongQi = hongQiCarFactory.CreateCar();
            hongQi.Go();

            //生產一輛奧迪汽車
            Car aoDi = aoDiCarFactory.CreateCar();
            aoDi.Go();

            //生產一輛賓士汽車
            Car benChi = benChiCarFactory.CreateCar();
            benChi.Go();

            Console.Read();
            #endregion
        }
    }
View Code

    運行結果如下:

    三、Factory Method模式的幾個要點

    Factory Method模式主要用於隔離類對象的使用者和具體類型之間的耦合關係。面對一個經常變化的具體類型,緊耦合關係會導致軟體的脆弱;

    Factory Method模式通過面向對象的手法,將所要創建的具體對象工作延遲到子類,從而實現一種擴展(而非更改)的策略,較好地解決了這種緊耦

合關係;

    Factory Method模式解決“單個對象”的需求變化;

    AbstractFactory模式解決“系列對象”的需求變化;

    Builder模式解決“對象部分”的需求變化;

    3.1、工廠方法模式的優點

    1)在工廠方法中,用戶只需要知道所要產品的具體工廠,無須關心具體的創建過程,甚至不需要具體產品類的類名。

    2)在系統增加新的產品時,我們只需要添加一個具體產品類和對應的實現工廠,無需對原工廠進行任何修改,很好地符合了“開閉原則”。

    3.2工廠方法模式的缺點

    1)每次增加一個產品時,都需要增加一個具體類和對象實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加

了系統具體類的依賴,這並不是什麼好事。

    3.3工廠方法模式的使用場合

    1)一個類不知道它所需要的對象的類。在工廠方法模式中,我們不需要具體產品的類名,我們只需要知道創建它的具體工廠即可。

    2)一個類通過其子類來指定創建那個對象。在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的介面,由其子類來確定具體要創建的對

象。在程式運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。

    3)將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定。

    四、.NET中實現了工廠方法的類

    .NET類庫中也有很多實現了工廠方法的類。例如在Asp.net中,處理程式對象是具體用來處理請求,當我們請求一個*.aspx的文件時,此時會映射到

System.Web.UI.PageHandlerFactory類上進行處理,而對*.ashx的請求將映射到System.Web.UI.SimpleHandlerFactory類中(這兩個類都是繼承於

IHttpHandlerFactory介面的),關於這點說明我們可在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”文件中找到相關定義:

    <add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>

    <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>

    <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>

    上面只摘選了部分配置文件,有時間大家可以自己去研究一下。

    下麵我們具體看下工廠方法模式在Asp.net中是如何實現的?對一個Index.aspx頁面發出請求時,將會調用PageHandlerFactory中GetHandler方法來

創建一個Index.aspx對象,它們之間的類圖關係如下:

    五、總結

    每種模式都有自己的使用場合,切記,如果使用錯誤,還不如不用。工廠方法模式通過面向對象編程中的多態性來將對象的創建延遲到具體工廠中,

從而解決了簡單工廠模式中存在的問題,也很好地符合了開放封閉原則(即對擴展開發,對修改封閉)。

    學習設計模式我們一定要謹記設計模式的幾大原則,否則是徒勞無功的。就像學務工一樣,我們要記心法。幾大原則就像獨孤九劍的劍訣,學會了,

變化無窮。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • """ 返回查詢集的方法稱為過濾器 all() 返回查詢集中所有數據 filter() 返回符合條件的數據 一、filter(鍵=值) 二、filter(鍵=值,鍵=值) #兩個關係為and 三、filter(鍵=值).filter(鍵=值) #兩個關係為and exclude()過濾掉符合邏輯的數 ...
  • from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): # __uni ...
  • 簡介 locale.h 頭文件定義了特定地域的設置,比如日期格式和貨幣符號。接下來我們將介紹一些巨集,以及一個重要的結構 struct lconv 和兩個重要的函數。 庫巨集 下麵列出了頭文件 locale.h 中定義的巨集,這些巨集將在下列的兩個函數中使用: | 序號 | 巨集 & 描述 | | : | : ...
  • 小伙伴們別急著立 Flag,讓員外幫你分析一下哪些技術正流行、哪些技術已過時後再立也不遲。時勢造英雄,技術也是一樣,新的技術層出不窮,要真正做到順勢而為卻又不隨波逐流(少學點保護頭髮)。 ...
  • 奮鬥沒有終點 ! 好好學習72變,因為將來 沒有人能替你阻擋81難 。 生如螻蟻,當有鴻鵠之志; 命如紙薄,應有不屈之心 。 ​ 今天被這句話觸動了,所以開篇分享給大家。雞湯有毒,但有時大家卻靠它激勵自己繼續前行! python開發GUI 程式員的自我救贖,使用python開發性格分析工具 這篇文章 ...
  • 在上面文章abp(net core)+easyui+efcore實現倉儲管理系統——ABP WebAPI與EasyUI結合增刪改查之七(三十三) 的學習之後,我們知道了ABP自動幫助我們生成了WebAPI介面,接下我們通過修改腳本文件中的新增、更新與刪除功能的腳本,通過這些WebAPI介面實現增刪改... ...
  • 上一小節,主要介紹了構建最小級別的安裝包,這個安裝包所做的事情很簡單,主要是打包好一些文件,然後放到用戶機器的某個位置下麵。 這個小節,主要是說安裝過程的各種行為如何使用Wix編寫。 CustomAction 1. 使用內建元素 CustomAction 註意到我們之前給用戶安裝過一個文件 Foob ...
  • 我們可以通過使用DataTime這個類來獲取當前的時間。通過調用類中的各種方法我們可以獲取不同的時間:如:日期(2019-01-09)、時間(16:02:12)、日期+時間(2019-01-09 16:11:10)等。 1.獲取日期和時間 DateTime.Now.ToString(); // 20 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...