工廠方法模式(講)_第1頁
工廠方法模式(講)_第2頁
工廠方法模式(講)_第3頁
工廠方法模式(講)_第4頁
工廠方法模式(講)_第5頁
已閱讀5頁,還剩14頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

本文格式為Word版,下載可任意編輯——工廠方法模式(講)

工廠方法模式(FactoryMethod)—對象創(chuàng)立型模式

工廠模式有以下幾種形態(tài):

簡單工廠(SimpleFactory)模式;

工廠方法(FactoryMethod)模式,又稱多形性工廠(PolymorphicFactory)模式;抽象工廠(AbstractFactory)模式,又稱工具箱(Kit或Toolkit)模式

概述

在軟件系統(tǒng)中,經(jīng)常面臨著“某個對象〞的創(chuàng)立工作,由于需求的變化,這個對象的具體實現(xiàn)經(jīng)常面臨著猛烈的變化,但是它卻擁有比較穩(wěn)定的接口。如何應(yīng)對這種變化?提供一種封裝機制來隔離出“這個易變對象〞的變化,從而保持系統(tǒng)中“其它依靠該對象的對象〞不隨著需求的改變而改變?這就是要說的FactoryMethod模式了。意圖

定義一個用戶創(chuàng)立對象的接口,讓子類決定實例化哪一個類。FactoryMethod使一個類的實例化延遲到其子類。工廠方法模式講解

在工廠方法模式中,核心的工廠類不再負責(zé)所有產(chǎn)品的創(chuàng)立,而是將具體創(chuàng)立工作交給子類去做。這個核心類僅僅負責(zé)給出具體工廠必需實現(xiàn)的接口,而不接觸哪一個產(chǎn)品類被實例化這種細節(jié)。這使得工廠方法模式可以允許系統(tǒng)在不修改工廠角色的狀況下引進新產(chǎn)品。在FactoryMethod模式中,工廠類與產(chǎn)品類往往具有平行的等級結(jié)構(gòu),它們之間一一對應(yīng)。

現(xiàn)在我們考慮一個日志記錄的例子(這里我們只是為了說明FactoryMethod模式,實際項目中的日志記錄不會這么去做,也要比這繁雜一些)。假定我們要設(shè)計日志

記錄的類,支持記錄的方法有FileLog和EventLog兩種方式。在這里我們先不談設(shè)計模式,那么這個日志記錄的類就很好實現(xiàn)了:1

///

2///日志記錄類3///4publicclassLog56

7publicvoidWriteEvent()8

{{

9Console.WriteLine(\10}11

12publicvoidWriteFile()13

{

14Console.WriteLine(\15}16

17publicvoidWrite(stringLogType)18

{

19switch(LogType.ToLower())20

{

21case\22WriteEvent();

23break;24

25case\26WriteFile();27break;28

29default:30break;31}32}33}34

這樣的程序結(jié)構(gòu)顯然不能符合我們的要求,假使我們增加一種新的日志記錄的方式DatabaseLog,那就要修改Log類,隨著記錄方式的變化,switch語句在不斷的變化,這樣就引起了整個應(yīng)用程序的不穩(wěn)定,進一步分析上面的代碼,發(fā)現(xiàn)對于EventLog和FileLog是兩種完全不同的記錄方式,它們之間不應(yīng)當(dāng)存在必然的聯(lián)系,而應(yīng)當(dāng)把它們分別作為單獨的對象來對待。1

///

2///EventLog類3///4publicclassEventLog5

{

6publicvoidWrite()7

{

8Console.WriteLine(\9}10}1112

///

13///FileLog類14///15publicclassFileLog16

{

17publicvoidWrite()18

{

19Console.WriteLine(\20}21}22

進一步抽象,為它們抽象出一個共同的父類,結(jié)構(gòu)圖如下:

實現(xiàn)代碼:1

///

2///Log類3///

4publicabstractclassLog5

{

6publicabstractvoidWrite();7}8

此時EventLog和FileLog類的代碼應(yīng)當(dāng)如下:1

///

2///EventLog類3///

4publicclassEventLog:Log5

{

6publicoverridevoidWrite()7

{

8Console.WriteLine(\9}10}11

///

12///FileLog類13///14publicclassFileLog:Log

15{

16publicoverridevoidWrite()17

{

18Console.WriteLine(\19}20}21

此時我們再看增加新的記錄日志方式DatabaseLog的時候,需要做哪些事情?只需要增加一個繼承父類Log的子類來實現(xiàn),而無需再去修改EventLog和FileLog類,這樣的設(shè)計滿足了類之間的層次關(guān)系,又很好的符合了面向?qū)ο笤O(shè)計中的單一職責(zé)原則,每一個類都只負責(zé)一件具體的事情。到這里似乎我們的設(shè)計很完美了,事實上我們還沒有看客戶程序如何去調(diào)用。在應(yīng)用程序中,我們要使用某一種日志記錄方式,可能會用到如下這樣的語句:

EventLogeventlog=newEventLog();eventlog.Write();

當(dāng)日志記錄的方式從EventLog變化為FileLog,我們就得修改所有程序代碼中出現(xiàn)上面語句的部分,這樣的工作量是可想而知的。此時就需要解耦具體的日志記錄方式和應(yīng)用程序。這就要引入FactoryMethod模式了,每一個日志記錄的對象就是工廠所生成的產(chǎn)品,既然有兩種記錄方式,那就需要兩個不同的工廠去生產(chǎn)了,代碼如下:1

///

2///EventFactory類3///

4publicclassEventFactory5

{

6publicEventLogCreate()7

{

8returnnewEventLog();9}10}11

///

12///FileFactory類13///14publicclassFileFactory15

{

16publicFileLogCreate()17

{

18returnnewFileLog();19}20}21

這兩個工廠和具體的產(chǎn)品之間是平行的結(jié)構(gòu),并一一對應(yīng),并在它們的基礎(chǔ)上抽象出一個公用的接口,結(jié)構(gòu)圖如下:

實現(xiàn)代碼如下:1

///

2///LogFactory類3///

4publicabstractclassLogFactory5

{

6publicabstractLogCreate();7}8

此時兩個具體工廠的代碼應(yīng)當(dāng)如下:1

///

2///EventFactory類3///

4publicclassEventFactory:LogFactory5

{

6publicoverrideEventLogCreate()

7{

8returnnewEventLog();9}10}11

///

12///FileFactory類13///

14publicclassFileFactory:LogFactory15

{

16publicoverrideFileLogCreate()17

{

18returnnewFileLog();19}20}21

這樣通過工廠方法模式我們把上面那對象創(chuàng)立工作封裝在了工廠中,此時我們似乎完成了整個FactoryMethod的過程。這樣達到了我們應(yīng)用程序和具體日志記錄對象之間解耦的目的了嗎?看一下此時客戶端程序代碼:1

///

2///App類

3///4publicclassApp5

{

6publicstaticvoidMain(string[]args)

7{

8LogFactoryfactory=newEventFactory();9

10Loglog=factory.Create();11

12log.Write();13}14}15

在客戶程序中,我們有效地避免了具體產(chǎn)品對象和應(yīng)用程序之間的耦合,可是我們也看到,增加了具體工廠對象和應(yīng)用程序之間的耦合。那這樣畢竟帶來什么好處呢?我們知道,在應(yīng)用程序中,Log對象的創(chuàng)立是頻繁的,在這里我們可以把LogFactoryfactory=newEventFactory();

這句話放在一個類模塊中,任何需要用到Log對象的地方依舊不變。要是換一種日志記錄方式,只要修改一處為:

LogFactoryfactory=newFileFactory();

其余的任何地方我們都不需要去修改。有人會說那還是修改代碼,其實在開發(fā)中我們很難避免修改,但是我們可以盡量做到只修改一處。結(jié)構(gòu)圖

適用性

在以下狀況下,適用于工廠方法模式:

1.當(dāng)一個類不知道它所必需創(chuàng)立的對象的類的時候。2.當(dāng)一個類希望由它的子類來指定它所創(chuàng)立的對象的時候。

3.當(dāng)類將創(chuàng)立對象的職責(zé)委托給多個幫助子類中的某一個,并且你希望將哪一個幫助

子類是代理者這一信息局部化的時候。

生活中的例子

工廠方法定義一個用于創(chuàng)立對象的接口,但是讓子類決定實例化哪個類。壓注成型演示了這種模式。塑料玩具制造商加工塑料粉,將塑料注入到希望形狀的模具中。玩具的類別(車,人物等等)是由模具決定的。

例子抽象工廠(Creator)角色:是工廠方法模式的核心,與應(yīng)用程序無關(guān)。任何在模式中創(chuàng)立的對象的工廠類必需實現(xiàn)這個接口。具體工廠(ConcreteCreator)角色:這是實現(xiàn)抽象工廠接口的具體工廠類,包含與應(yīng)用程序密切相關(guān)的規(guī)律,并且受到應(yīng)用程序調(diào)用以創(chuàng)立產(chǎn)品對象。在上圖中有兩個這樣的角色:BulbCreator與TubeCreator。抽象產(chǎn)品(Product)角色:工廠方法模式所創(chuàng)立的對象的超類型,也就是產(chǎn)品對象的共同父類或共同擁有的接口。在上圖中,這個角色是Light。具體產(chǎn)品(ConcreteProduct)角色:這個角色實現(xiàn)了抽象產(chǎn)品角色所定義的接口。某具體產(chǎn)品有專門的具體工廠創(chuàng)立,它們之間往往一一對應(yīng)。程序舉例:usingSystem;publicabstractclassLight{publicabstractvoidTurnOn();publicabstractvoidTurnOff();}publicclassBulbLight:Light{publicoverridevoidTurnOn(){Console.WriteLine(\publicoverridevoidTurnOff(){Console.WriteLine(\}publicclassTubeLight:Light{publicoverridevoidTurnOn(){Console.WriteLine(\publicoverridevoidTurnOff(){Console.WriteLine(\}publicabstractclassCreator{publicabstractLightfactory();}publicclassBulbCreator:Creator{publicoverrideLightfactory(){returnnewBulbLight();}}publicclassTubeCreator:Creator{publicoverrideLightfactory(){returnnewTubeLight();}}publicclassClient{publicstaticvoidMain(){Creatorc1=newBulbCreator();Creatorc2=newTubeCreator();Lightl1=c1.factory();Lightl2=c2.factory();l1.TurnOn();l1.TurnOff();Console.WriteLine(\l2.TurnOn();l2.TurnOff();}}工廠方法的活動序列圖

活動過程包括:客戶端創(chuàng)立BulbCreator對象,客戶端持有此對象的類型是Creator,而實際類型是BulbCreator。然后客戶端調(diào)用BulbCreator的factory方法,之后BulbCreator調(diào)用BulbLight的構(gòu)造函數(shù)創(chuàng)造出產(chǎn)品BulbLight對象。實現(xiàn)要點

1.FactoryMethod模式的兩種狀況:一是Creator類是一個抽象類且它不提供它所聲明的工廠方法的實現(xiàn);二是Creator是一個具體的類且它提供一個工廠方法的缺省實現(xiàn)。

2.工廠方法是可以帶參數(shù)的。

3.工廠的作用并不僅僅只是創(chuàng)立一個對象,它還可以做對象的初始化,參數(shù)的設(shè)置等。效果

1.用工廠方法在一個類的內(nèi)部創(chuàng)立對象尋常比直接創(chuàng)立對象更靈活。

2.FactoryMethod模式通過面向?qū)ο蟮氖址?,將所要?chuàng)立的具體對象的創(chuàng)立工作延

遲到了子類,從而提供了一種擴展的策略,較好的解決了這種緊耦合的關(guān)系。總結(jié)

FactoryMethod模式是設(shè)計模式中應(yīng)用最為廣泛的模式,通過本文,相信讀者已經(jīng)對它有了一定的認識。然而我們要明確的是:在面向?qū)ο蟮木幊讨?,對象的?chuàng)立工作十分簡單,對象的創(chuàng)立時機卻很重要。FactoryMethod要解決的就是對象的創(chuàng)立時機問題,它提供了一種擴展的策略,很好地符合了開放封閉原則。

當(dāng)發(fā)現(xiàn)系統(tǒng)只用一個產(chǎn)品類等級不足以描述所有的產(chǎn)品類,包括以后可能要添加的新的產(chǎn)品類時,就應(yīng)當(dāng)考慮采用工廠方法模式。由于工廠方法模式可以容大量個實的工廠類,以每一個工廠類負責(zé)每一個產(chǎn)品類等級,因此這種模式可以容納所有的產(chǎn)品等級。

區(qū)別:

關(guān)于工廠方法的一點探討,我們知道工廠方法屬于類型創(chuàng)立模式,而抽象工廠屬于對象創(chuàng)立模式,并且所謂的類創(chuàng)立模式就是把創(chuàng)立工作延遲到子類,而對象創(chuàng)立模式則將延遲到另一個對象。

工廠方法模式的意義是定義一個創(chuàng)立產(chǎn)品對象的工廠接口,將實際創(chuàng)立工作推遲到子類當(dāng)中。核心工廠類不再負責(zé)產(chǎn)品的創(chuàng)立,這樣核心類成為一個抽象工廠角色,僅負責(zé)具體工廠子類必需實現(xiàn)的接口

工廠解決的問題是一個系列的對象的創(chuàng)立;工廠方法模式在農(nóng)場系統(tǒng)中的實現(xiàn)1背景

在簡單工廠模式中,有個全能的園丁,控制所有作物的種植、生長和收獲?,F(xiàn)在農(nóng)場規(guī)模變大了,管理更加專業(yè)化了。過去全能的園丁沒有了,每一種作物都有專門的園丁管理,形成了規(guī)?;蛯I(yè)化生產(chǎn)。

2系統(tǒng)設(shè)計機構(gòu)圖

3實現(xiàn)源碼

3.1水果產(chǎn)品接口Fruit.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:Fruit.java*ReadMe:水果接口*/

publicinterfaceFruit{/***種植*/

voidplant();/***生長*/

voidgrow();/***收獲

*/

voidharvest();}

3.2具體產(chǎn)品蘋果Apple.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:Apple.java*ReadMe:水果工廠的產(chǎn)品:蘋果*/

publicclassAppleimplementsFruit{privateinttreeAge;/***種植*/

publicvoidplant(){

System.out.println(\}/***生長*/

publicvoidgrow(){

System.out.println(\}

/***收獲*/

publicvoidharvest(){

System.out.println(\}/**

*@return返回樹齡*/

publicintgetTreeAge(){returntreeAge;}/***設(shè)置樹齡*/

publicvoidsetTreeAge(inttreeAge){this.treeAge=treeAge;}}

3.3具體產(chǎn)品葡萄:Grape.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:Grape.java*ReadMe:水果工廠的產(chǎn)品:葡萄

*/

publicclassGrapeimplementsFruit{privatebooleanseedless;//是否有籽/***種植*/

publicvoidplant(){

System.out.println(\}/***生長*/

publicvoidgrow(){

System.out.println(\}/***收獲*/

publicvoidharvest(){

System.out.println(\}/**

*@return是否有籽*/

publicbooleangetSeedless(){

returnseedless;}/**

*有無籽的賦值方法*/

publicvoidsetSeedless(booleanseedless){this.seedless=seedless;}/***輔助方法*/

publicstaticvoidlog(Stringmsg){System.out.println(msg);}}

3.4具體產(chǎn)品草莓:Strawberry.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:Strawberry.java*ReadMe:水果工廠的產(chǎn)品:草莓*/

publicclassStrawberryimplementsFruit{/***生長

*/

publicvoidgrow(){

System.out.println(\}/***收獲*/

publicvoidharvest(){

System.out.println(\}/***種植*/

publicvoidplant(){

System.out.println(\}/***輔助方法*/

publicstaticvoidlog(Stringmsg){System.out.println(msg);}}

3.5水果工廠接口:FruitGardener.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:FruitGardener.java*ReadMe:水果工廠接口*/

publicinterfaceFruitGardener{/***工廠方法*

*@return水果*/

publicFruitfactory();}

3.6蘋果工廠:AppleGardener.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:AppleGardener.java

*工廠模式--工廠方法模式--一般性模式(農(nóng)場應(yīng)用)*ReadMe:蘋果工廠方法*/

publicclassAppleGardenerimplementsFruitGardener{/**

*工廠方法*

*@return蘋果*/

publicFruitfactory(){Fruitf=newApple();

System.out.println(\水果工廠(AppletGardener)成功創(chuàng)立一個水果:蘋果!\returnf;}}

3.7葡萄工廠:GrapeGardener.java

packagecom.lavasoft.patterns.factorymethod.ybms;/**

*CreatedbyIntelliJIDEA.*FileName:GrapeGardener.java

*工廠模式--工廠方法模式--一般性模式(農(nóng)場應(yīng)用)*ReadMe:添加說明*/

publicclassGrapeGardenerimplementsFruitGardener{/***工廠方法*

*@return葡萄*/

publicFruitfactory(){Fruitf=newGrape();

System.out.println(\水果工廠(GrapeGardener)成功創(chuàng)立一個水果:葡萄!\returnf;}}

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論