C# 設(shè)計(jì)模式-工廠方法模式[轉(zhuǎn)]

原文作者:Hilary-He

工廠方法模式簡介:
工廠方法(Factory Method)模式的意義是定義一個(gè)創(chuàng)建產(chǎn)品對(duì)象的工廠接口,將實(shí)際創(chuàng)建工作推遲到子類當(dāng)中。核心工廠類不再負(fù)責(zé)產(chǎn)品的創(chuàng)建,這樣核心類成為一個(gè)抽象工廠角色怎茫,僅負(fù)責(zé)具體工廠子類必須實(shí)現(xiàn)的接口摆尝,這樣進(jìn)一步抽象化的好處是使得工廠方法模式可以使系統(tǒng)在不修改具體工廠角色的情況下引進(jìn)新的產(chǎn)品。

過程方法模式結(jié)構(gòu):


image.png

抽象工廠角色:是工廠方法模式的核心鹅很,與應(yīng)用程序無關(guān)。任何在模式中創(chuàng)建的對(duì)象的工廠類必須實(shí)現(xiàn)這個(gè)接口罪帖。
具體工廠角色:這是實(shí)現(xiàn)抽象工廠接口的具體工廠類促煮,包含與應(yīng)用程序密切相關(guān)的邏輯,并且受到應(yīng)用程序調(diào)用以創(chuàng)建產(chǎn)品對(duì)象
抽象產(chǎn)品角色:工廠方法模式所創(chuàng)建的對(duì)象的超類型整袁,也就是產(chǎn)品對(duì)象的共同父類或共同擁有的接口菠齿。在上圖中,這個(gè)角色是Light坐昙。
具體產(chǎn)品角色:這個(gè)角色實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口绳匀。某具體產(chǎn)品有專門的具體工廠創(chuàng)建,它們之間往往一一對(duì)應(yīng)。

在上一篇博文【C#設(shè)計(jì)模式-簡單工廠模式】中疾棵,我們使用簡單工廠模式實(shí)現(xiàn)了:

如果有一個(gè)住戶管理系統(tǒng)戈钢,里面的住戶類型是可變的,每一種租戶類型的租金計(jì)算公式都存在差異
例如:A類型的住戶租金額=天數(shù)單價(jià)+績效0.005是尔;B類型的住戶租金額=月份(每月價(jià)格+performance0.001)
這里我們雖然實(shí)現(xiàn)了客戶的需求殉了,但是如果客戶后期需要增加了C類型商店和D類型商店,而它們的算法要求又不一樣拟枚,
這個(gè)時(shí)候我們就需要進(jìn)行C薪铜,D類型商店的創(chuàng)建,并繼承Ishop接口恩溅,實(shí)現(xiàn)里面的方法隔箍,
同時(shí)還得繼續(xù)修改工廠類在switc中增加case進(jìn)行捕捉創(chuàng)建相應(yīng)的商店對(duì)象,一旦出現(xiàn)這樣的情況脚乡,是不利于程序的擴(kuò)展性和項(xiàng)目后期的維護(hù)性的蜒滩。
現(xiàn)在使用工廠方法模式可以很好的解決這一問題。不多說上代碼每窖。
1.分析:商店有共同的行為特征帮掉,都要進(jìn)行店鋪?zhàn)饨鹩?jì)算行為,我們抽象了Ishop ,里面有待實(shí)現(xiàn)的計(jì)算商店租金方法行為窒典。

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.我們實(shí)現(xiàn)Isho接口里面的方法,創(chuàng)建A,B類型店鋪稽莉。

using FactoryEntiy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProductEnity
{
    /// <summary>
    /// 繼承商店接口瀑志,實(shí)現(xiàn)里面的行為方法,即算法
    /// </summary>
    public class Ashop:Ishop
    {
        /// <summary>
        /// /// A類型商店租金額污秆,天數(shù)*單價(jià)+績效*0.005
        /// </summary>
        /// <param name="days">天數(shù)</param>
        /// <param name="dayprice">每天單價(jià)</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>
    /// 繼承商店接口劈猪,實(shí)現(xiàn)里面的行為方法,即算法
    /// </summary>
    public class Bshop:Ishop
    {
        /// <summary>
        /// B類型商店的租金=月份*(每月價(jià)格+performance*0.001)
        /// </summary>
        /// <param name="month">月數(shù)</param>
        /// <param name="monthprice">月單價(jià)</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.現(xiàn)在考慮在什么情況下創(chuàng)建商店的實(shí)體良拼,對(duì)不同的商店進(jìn)行租金計(jì)算战得,并且方便以后的增加和修改。

于是我們創(chuàng)建IFactroy接口庸推,里面有待實(shí)現(xiàn)的創(chuàng)建商店對(duì)象的方法常侦。

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

4.現(xiàn)在我們就可以繼承自IFactory,實(shí)現(xiàn)里面創(chuàng)建對(duì)應(yīng)的商店對(duì)象了贬媒。

using FactoryEntiy;
using FactoryMethod;
using ProductEnity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProductEnity
{
    /// <summary>
    /// 繼承工廠類聋亡,創(chuàng)建A類型商店實(shí)體
    /// </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>
    /// 繼承工廠類,創(chuàng)建B類型商店實(shí)體
    /// </summary>
    public class CreateBshop : IFactory
    {
        public Ishop CreateShop()
        {
            return new Bshop();
        }
    }
}

5.之后根據(jù)當(dāng)前的商店類型進(jìn)行判斷际乘,該類型的商店應(yīng)該進(jìn)行哪一種算法:

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為創(chuàng)建商店類名稱坡倔,此處=CreateAshop
            IFactory af = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + shopname);
            //第一個(gè)ProductEnity是dll的名稱,第二個(gè)ProductEnity是項(xiàng)目的命名空間。
            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可以保存為配置或者存在數(shù)據(jù)庫中罪塔,
            //注意該保存字符串應(yīng)該與項(xiàng)目中創(chuàng)建的類名一樣投蝉,
            //否則反射的方式會(huì)找不到該項(xiàng)目下的類。
            Ishop Bs = bf.CreateShop(); total = Bs.Getrent(30, 300, 2000); //30 天/100元 日平均績效為2000
            Console.WriteLine("該A類型商店的租金為:" + total);
        }
    }
}

這里我們使用反射的方式創(chuàng)建對(duì)象征堪,替換了之前的工廠類通過switch創(chuàng)建對(duì)象的方式瘩缆,有利于后面的新類型商店增加和算法修改增加和維護(hù)

以后在項(xiàng)目需求在有變革,我們只需要重新在項(xiàng)目中增加C,D類型商店请契,繼承Ishop實(shí)現(xiàn)里面的方法咳榜,同時(shí),添加繼承IFactroy接口爽锥,創(chuàng)建對(duì)應(yīng)的商店對(duì)象編譯該項(xiàng)目的

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

整個(gè)項(xiàng)目的結(jié)構(gòu)圖如下:

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末臣樱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子腮考,更是在濱河造成了極大的恐慌雇毫,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,332評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踩蔚,死亡現(xiàn)場離奇詭異棚放,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)馅闽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門飘蚯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人福也,你說我怎么就攤上這事局骤。” “怎么了暴凑?”我有些...
    開封第一講書人閱讀 157,812評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵峦甩,是天一觀的道長。 經(jīng)常有香客問我现喳,道長凯傲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,607評(píng)論 1 284
  • 正文 為了忘掉前任拿穴,我火速辦了婚禮泣洞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘默色。我一直安慰自己球凰,他們只是感情好狮腿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,728評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呕诉,像睡著了一般缘厢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甩挫,一...
    開封第一講書人閱讀 49,919評(píng)論 1 290
  • 那天贴硫,我揣著相機(jī)與錄音,去河邊找鬼伊者。 笑死英遭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的亦渗。 我是一名探鬼主播挖诸,決...
    沈念sama閱讀 39,071評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼法精!你這毒婦竟也來了多律?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,802評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤搂蜓,失蹤者是張志新(化名)和其女友劉穎狼荞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帮碰,經(jīng)...
    沈念sama閱讀 44,256評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡相味,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,576評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了殉挽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攻走。...
    茶點(diǎn)故事閱讀 38,712評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖此再,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玲销,我是刑警寧澤输拇,帶...
    沈念sama閱讀 34,389評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站贤斜,受9級(jí)特大地震影響策吠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘩绒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,032評(píng)論 3 316
  • 文/蒙蒙 一猴抹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锁荔,春花似錦蟀给、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽择克。三九已至,卻和暖如春前普,著一層夾襖步出監(jiān)牢的瞬間肚邢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評(píng)論 1 266
  • 我被黑心中介騙來泰國打工拭卿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骡湖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,473評(píng)論 2 360
  • 正文 我出身青樓峻厚,卻偏偏與公主長得像响蕴,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子目木,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,606評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計(jì)模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計(jì)原則時(shí)需要注意以下幾點(diǎn):a) 高內(nèi)聚换途、低耦合和單一職能的“沖突”實(shí)際上,這兩者...
    彥幀閱讀 3,737評(píng)論 0 14
  • 設(shè)計(jì)模式匯總 一刽射、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用军拟、多...
    MinoyJet閱讀 3,922評(píng)論 1 15
  • 簡單工廠模式雖然簡單,但存在一個(gè)很嚴(yán)重的問題誓禁。當(dāng)系統(tǒng)中需要引入新產(chǎn)品時(shí)懈息,由于靜態(tài)工廠方法通過所傳入?yún)?shù)的不同來創(chuàng)建...
    justCode_閱讀 1,181評(píng)論 1 9
  • 鏈接:https://github.com/WiKi123/DesignPattern作者: WiKi123(gi...
    樹懶啊樹懶閱讀 3,476評(píng)論 0 2
  • 那天雪很大,以致那年的后半個(gè)冬天我都沒有去過學(xué)校摹恰。在我還什么都不懂的年紀(jì)里辫继,對(duì)不用去學(xué)校還能放心睡懶覺這種事兒真的...
    無寫不成詩閱讀 135評(píng)論 0 0