C# 設計模式-工廠方法模式[轉]

原文作者:Hilary-He

工廠方法模式簡介:
工廠方法(Factory Method)模式的意義是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類當中。核心工廠類不再負責產品的創建,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。

過程方法模式結構:


image.png

抽象工廠角色:是工廠方法模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現這個接口。
具體工廠角色:這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,并且受到應用程序調用以創建產品對象
抽象產品角色:工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。在上圖中,這個角色是Light。
具體產品角色:這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創建,它們之間往往一一對應。

在上一篇博文【C#設計模式-簡單工廠模式】中,我們使用簡單工廠模式實現了:

如果有一個住戶管理系統,里面的住戶類型是可變的,每一種租戶類型的租金計算公式都存在差異
例如:A類型的住戶租金額=天數單價+績效0.005;B類型的住戶租金額=月份(每月價格+performance0.001)
這里我們雖然實現了客戶的需求,但是如果客戶后期需要增加了C類型商店和D類型商店,而它們的算法要求又不一樣,
這個時候我們就需要進行C,D類型商店的創建,并繼承Ishop接口,實現里面的方法,
同時還得繼續修改工廠類在switc中增加case進行捕捉創建相應的商店對象,一旦出現這樣的情況,是不利于程序的擴展性和項目后期的維護性的。
現在使用工廠方法模式可以很好的解決這一問題。不多說上代碼。
1.分析:商店有共同的行為特征,都要進行店鋪租金計算行為,我們抽象了Ishop ,里面有待實現的計算商店租金方法行為。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace FactoryEntiy
{
    public interface Ishop
    {
        double Getrent(int days, double dayprice, double performance);
    }
}
2.我們實現Isho接口里面的方法,創建A,B類型店鋪。

using FactoryEntiy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProductEnity
{
    /// <summary>
    /// 繼承商店接口,實現里面的行為方法,即算法
    /// </summary>
    public class Ashop:Ishop
    {
        /// <summary>
        /// /// A類型商店租金額,天數*單價+績效*0.005
        /// </summary>
        /// <param name="days">天數</param>
        /// <param name="dayprice">每天單價</param>
        /// <param name="performance">日平均績效</param>
        /// <returns></returns>
        public double Getrent(int days, double dayprice, double performance)
        {
            Console.WriteLine("A商店的租金算法");
            return days * dayprice + performance * 0.01;
        }
    }
}

using FactoryEntiy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProductEnity
{
    /// <summary>
    /// 繼承商店接口,實現里面的行為方法,即算法
    /// </summary>
    public class Bshop:Ishop
    {
        /// <summary>
        /// B類型商店的租金=月份*(每月價格+performance*0.001)
        /// </summary>
        /// <param name="month">月數</param>
        /// <param name="monthprice">月單價</param>
        /// <param name="performance">月平均績效</param>
        /// <returns></returns>
        public double Getrent(int month, double monthprice, double performance)
        {
            Console.WriteLine("B商店的租金算法");
            return month * (monthprice + performance * 0.001);
        }
    }
}

3.現在考慮在什么情況下創建商店的實體,對不同的商店進行租金計算,并且方便以后的增加和修改。

于是我們創建IFactroy接口,里面有待實現的創建商店對象的方法。

using FactoryEntiy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace FactoryMethod
{
    /// <summary>
    /// 工廠類,創建商店類型實體
    /// </summary>
    public interface IFactory
    {
        Ishop CreateShop();
    }
}

4.現在我們就可以繼承自IFactory,實現里面創建對應的商店對象了。

using FactoryEntiy;
using FactoryMethod;
using ProductEnity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProductEnity
{
    /// <summary>
    /// 繼承工廠類,創建A類型商店實體
    /// </summary>
    public class CreateAshop : IFactory
    {
        public Ishop CreateShop()
        {
            return new Ashop();
        }
    }
}
 
using FactoryEntiy;
using FactoryMethod;
using ProductEnity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProductEnity
{
    /// <summary>
    /// 繼承工廠類,創建B類型商店實體
    /// </summary>
    public class CreateBshop : IFactory
    {
        public Ishop CreateShop()
        {
            return new Bshop();
        }
    }
}

5.之后根據當前的商店類型進行判斷,該類型的商店應該進行哪一種算法:

using FactoryEntiy;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
 
namespace FactoryMethod.App
{
    class Program
    {
        static void Main(string[] args)
        {
            string shopname = ConfigurationManager.AppSettings["CreateShopClassName"];
            //shopname為創建商店類名稱,此處=CreateAshop
            IFactory af = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + shopname);
            //第一個ProductEnity是dll的名稱,第二個ProductEnity是項目的命名空間。
            Ishop As = af.CreateShop(); double total = As.Getrent(30, 300, 2000); //30 天/100元 日平均績效為2000 
            Console.WriteLine("該A類型商店的租金為:" + total); 
            
            Console.WriteLine("=============");
            IFactory bf = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + "CreateBshop");
            //CreateBshop可以保存為配置或者存在數據庫中,
            //注意該保存字符串應該與項目中創建的類名一樣,
            //否則反射的方式會找不到該項目下的類。
            Ishop Bs = bf.CreateShop(); total = Bs.Getrent(30, 300, 2000); //30 天/100元 日平均績效為2000
            Console.WriteLine("該A類型商店的租金為:" + total);
        }
    }
}

這里我們使用反射的方式創建對象,替換了之前的工廠類通過switch創建對象的方式,有利于后面的新類型商店增加和算法修改增加和維護

以后在項目需求在有變革,我們只需要重新在項目中增加C,D類型商店,繼承Ishop實現里面的方法,同時,添加繼承IFactroy接口,創建對應的商店對象編譯該項目的

ProductEnity.dll,以后再進行計算該C,D類型的商店算法就可以通過反射的方式進行計算,不需要修改原來的工程類代碼。

整個項目的結構圖如下:

image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容

  • 設計模式概述 在學習面向對象七大設計原則時需要注意以下幾點:a) 高內聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,765評論 0 14
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,960評論 1 15
  • 簡單工廠模式雖然簡單,但存在一個很嚴重的問題。當系統中需要引入新產品時,由于靜態工廠方法通過所傳入參數的不同來創建...
    justCode_閱讀 1,195評論 1 9
  • 鏈接:https://github.com/WiKi123/DesignPattern作者: WiKi123(gi...
    樹懶啊樹懶閱讀 3,575評論 0 2
  • 那天雪很大,以致那年的后半個冬天我都沒有去過學校。在我還什么都不懂的年紀里,對不用去學校還能放心睡懶覺這種事兒真的...
    無寫不成詩閱讀 144評論 0 0