.Net創(chuàng)建型設(shè)計(jì)模式之工廠方法模式(Factory?Method)
一、動(dòng)機(jī)(Motivation)
在軟件系統(tǒng)創(chuàng)建過(guò)程中,經(jīng)常面臨著“某個(gè)對(duì)象”的創(chuàng)建工作:由于需求的變化,這個(gè)對(duì)象(的具體實(shí)現(xiàn))經(jīng)常面臨著劇烈的變化,但是它卻擁有比較穩(wěn)定的接口。
如何應(yīng)對(duì)這種變化?如何提供一種“封裝機(jī)制”來(lái)隔離出“這個(gè)易變對(duì)象”的變化,從而保持系統(tǒng)中“其他依賴(lài)對(duì)象的對(duì)象”不隨著需求改變而改變?
二、意圖(Intent)
定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)。Factory Method使得一個(gè)類(lèi)的實(shí)例化延遲到子類(lèi)。——《設(shè)計(jì)模式》GoF
三、結(jié)構(gòu)(Structure)
四、模式的組成
可以看出,在工廠方法模式的結(jié)構(gòu)圖有以下角色:
(1)、抽象工廠角色(Creator): 充當(dāng)抽象工廠角色,定義工廠類(lèi)所具有的基本的操作,任何具體工廠都必須繼承該抽象類(lèi)。
(2)、具體工廠角色(ConcreteCreator):充當(dāng)具體工廠角色,該類(lèi)必須繼承抽象工廠角色,實(shí)現(xiàn)抽象工廠定義的方法,用來(lái)創(chuàng)建具體產(chǎn)品。
(3)、抽象產(chǎn)品角色(Product):充當(dāng)抽象產(chǎn)品角色,定義了產(chǎn)品類(lèi)型所有具有的基本操作,具體產(chǎn)品必須繼承該抽象類(lèi)。
(4)、具體產(chǎn)品角色(ConcreteProduct):充當(dāng)具體產(chǎn)品角色,實(shí)現(xiàn)抽象產(chǎn)品類(lèi)對(duì)定義的抽象方法,由具體工廠類(lèi)創(chuàng)建,它們之間有一一對(duì)應(yīng)的關(guān)系。
五、工廠方法模式的代碼實(shí)現(xiàn)
【簡(jiǎn)單工廠模式】的問(wèn)題是:如果有新的需求就需要修改工廠類(lèi)里面創(chuàng)建產(chǎn)品對(duì)象實(shí)例的那個(gè)方法的實(shí)現(xiàn)代碼,在面向?qū)ο笤O(shè)計(jì)一個(gè)原則就是哪里有變化,我就封裝哪里。
為了應(yīng)對(duì)改變,我們需要把Car先變成抽象類(lèi)。
public abstract class Car { public abstract void startup(); public abstract void run(); public abstract void stop(); } internal class BenzCar : Car { public override void startup() { Console.WriteLine("BenzCar Startup!"); } public override void run() { Console.WriteLine("BenzCar Running!"); } public override void stop() { Console.WriteLine("BenzCar Stopped!"); } } internal class HondaCar : Car { public override void startup() { Console.WriteLine("HondaCar Startup!"); } public override void run() { Console.WriteLine("HondaCar Running!"); } public override void stop() { Console.WriteLine("HondaCar Stopped!"); } } public abstract class CarFactory { public abstract Car CreatCar(); } internal class BenzCarFactory : CarFactory { public override Car CreatCar() { return new BenzCar(); } } internal class HondaCarFactory : CarFactory { public override Car CreatCar() { return new HondaCar(); } }
我們?cè)诳蛻?hù)程序使用的時(shí)候,把所有的Car都換成抽象的AbstractCar,這樣客戶(hù)程序就不需要了解具體測(cè)試的是哪個(gè)Car了。客戶(hù)程序如下:
internal class CarTestFrameWork { public void DoTest(CarFactory carFactory) { Car car = carFactory.CreatCar(); car.startup(); car.run(); car.stop(); } }
在應(yīng)用程序調(diào)用的時(shí)候,傳入客戶(hù)程序的工廠應(yīng)該是具體的HongqiCarFactory工廠。當(dāng)想換具體Car的時(shí)候,只需要?jiǎng)?chuàng)建一個(gè)新的Car繼承自AbstractCar,并新建一個(gè)具體CarFactory工廠繼承自抽象CarFactory。然后在具體的應(yīng)用中把具體的Car工廠參數(shù)修改即可。當(dāng)然,完全可以讓具體應(yīng)用的代碼也不用修改,把變化轉(zhuǎn)嫁到配置文件中去。
internal class Test { public static void Main() { CarTestFrameWork cf = new CarTestFrameWork(); cf.DoTest(new BenzCarFactory()); cf.DoTest(new HondaCarFactory()); } }
六、Factory Method模式的幾個(gè)要點(diǎn)
Factory Method模式主要用于隔離類(lèi)對(duì)象的使用者和具體類(lèi)型之間的耦合關(guān)系。面對(duì)一個(gè)經(jīng)常變化的具體類(lèi)型,緊耦合關(guān)系會(huì)導(dǎo)致軟件的脆弱。
Factory Method模式通過(guò)面向?qū)ο蟮氖址?,將所要?jiǎng)?chuàng)建的具體對(duì)象工作延遲到子類(lèi),從而實(shí)現(xiàn)一種擴(kuò)展(而非更改)的策略,較好地解決了這種緊耦合關(guān)系。
- Factory Method模式解決“單個(gè)對(duì)象”的需求變化;
- AbstractFactory模式解決“系列對(duì)象”的需求變化;
- Builder模式解決“對(duì)象部分”的需求變化;
1、工廠方法模式的優(yōu)點(diǎn):
(1)、 在工廠方法中,用戶(hù)只需要知道所要產(chǎn)品的具體工廠,無(wú)須關(guān)系具體的創(chuàng)建過(guò)程,甚至不需要具體產(chǎn)品類(lèi)的類(lèi)名。
(2)、在系統(tǒng)增加新的產(chǎn)品時(shí),我們只需要添加一個(gè)具體產(chǎn)品類(lèi)和對(duì)應(yīng)的實(shí)現(xiàn)工廠,無(wú)需對(duì)原工廠進(jìn)行任何修改,很好地符合了“開(kāi)閉原則”。
2、工廠方法模式的缺點(diǎn):
(1)、每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類(lèi)和對(duì)象實(shí)現(xiàn)工廠,是的系統(tǒng)中類(lèi)的個(gè)數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)也增加了系統(tǒng)具體類(lèi)的依賴(lài)。這并不是什么好事。
3、工廠方法模式使用的場(chǎng)景:
(1)、一個(gè)類(lèi)不知道它所需要的對(duì)象的類(lèi)。在工廠方法模式中,我們不需要具體產(chǎn)品的類(lèi)名,我們只需要知道創(chuàng)建它的具體工廠即可。
(2)、一個(gè)類(lèi)通過(guò)其子類(lèi)來(lái)指定創(chuàng)建那個(gè)對(duì)象。在工廠方法模式中,對(duì)于抽象工廠類(lèi)只需要提供一個(gè)創(chuàng)建產(chǎn)品的接口,而由其子類(lèi)來(lái)確定具體要?jiǎng)?chuàng)建的對(duì)象,在程序運(yùn)行時(shí),子類(lèi)對(duì)象將覆蓋父類(lèi)對(duì)象,從而使得系統(tǒng)更容易擴(kuò)展。
(3)、將創(chuàng)建對(duì)象的任務(wù)委托給多個(gè)工廠子類(lèi)中的某一個(gè),客戶(hù)端在使用時(shí)可以無(wú)須關(guān)心是哪一個(gè)工廠子類(lèi)創(chuàng)建產(chǎn)品子類(lèi),需要時(shí)再動(dòng)態(tài)指定。
七、.NET中實(shí)現(xiàn)了工廠方法的類(lèi)
.NET 類(lèi)庫(kù)中也有很多實(shí)現(xiàn)了工廠方法的類(lèi),例如Asp.net中,處理程序?qū)ο笫蔷唧w用來(lái)處理請(qǐng)求,當(dāng)我們請(qǐng)求一個(gè)*.aspx的文件時(shí),此時(shí)會(huì)映射到System.Web.UI.PageHandlerFactory類(lèi)上進(jìn)行處理,而對(duì)*.ashx的請(qǐng)求將映射到System.Web.UI.SimpleHandlerFactory類(lèi)中(這兩個(gè)類(lèi)都是繼承于IHttpHandlerFactory接口的),關(guān)于這點(diǎn)說(shuō)明我們可以在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”文件中找到相關(guān)定義,具體定義如下:
<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"/>
配置文件截圖了一部分,有時(shí)間大家可以自己去研究一下。
下面我們就具體看下工廠方法模式在Asp.net中是如何實(shí)現(xiàn)的,如果對(duì)一個(gè)Index.aspx頁(yè)面發(fā)出請(qǐng)求時(shí),將會(huì)調(diào)用PageHandlerFactory中GetHandler方法來(lái)創(chuàng)建一個(gè)Index.aspx對(duì)象,它們之間的類(lèi)圖關(guān)系如下:
到此這篇關(guān)于.Net設(shè)計(jì)模式之工廠方法模式(Factory Method)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
.Net?Core中使用MongoDB搭建集群與項(xiàng)目實(shí)戰(zhàn)
本文詳細(xì)講解了.Net?Core中使用MongoDB搭建集群與項(xiàng)目實(shí)戰(zhàn),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02ASP.NET 5已終結(jié),迎來(lái)ASP.NET Core 1.0和.NET Core 1.0
命名是非常困難的事情,微軟這次為了和ASP.NET4.6做區(qū)分,采用了全新的命名方式ASP.NET Core 1.0,它是一個(gè)全新的框架。2016-03-03.Net結(jié)構(gòu)型設(shè)計(jì)模式之橋接模式(Bridge)
這篇文章介紹了.Net結(jié)構(gòu)型設(shè)計(jì)模式之橋接模式(Bridge),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05讓Sqlite脫離VC++ Runtime獨(dú)立運(yùn)行的方法
這篇文章主要介紹了讓Sqlite脫離VC++ Runtime獨(dú)立運(yùn)行的方法,需要的朋友可以參考下2014-07-07