




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
本文格式為Word版,下載可任意編輯——工廠方法模式(講)
工廠方法模式(FactoryMethod)—對象創立型模式
工廠模式有以下幾種形態:
簡單工廠(SimpleFactory)模式;
工廠方法(FactoryMethod)模式,又稱多形性工廠(PolymorphicFactory)模式;抽象工廠(AbstractFactory)模式,又稱工具箱(Kit或Toolkit)模式
概述
在軟件系統中,經常面臨著“某個對象〞的創立工作,由于需求的變化,這個對象的具體實現經常面臨著猛烈的變化,但是它卻擁有比較穩定的接口。如何應對這種變化?提供一種封裝機制來隔離出“這個易變對象〞的變化,從而保持系統中“其它依靠該對象的對象〞不隨著需求的改變而改變?這就是要說的FactoryMethod模式了。意圖
定義一個用戶創立對象的接口,讓子類決定實例化哪一個類。FactoryMethod使一個類的實例化延遲到其子類。工廠方法模式講解
在工廠方法模式中,核心的工廠類不再負責所有產品的創立,而是將具體創立工作交給子類去做。這個核心類僅僅負責給出具體工廠必需實現的接口,而不接觸哪一個產品類被實例化這種細節。這使得工廠方法模式可以允許系統在不修改工廠角色的狀況下引進新產品。在FactoryMethod模式中,工廠類與產品類往往具有平行的等級結構,它們之間一一對應。
現在我們考慮一個日志記錄的例子(這里我們只是為了說明FactoryMethod模式,實際項目中的日志記錄不會這么去做,也要比這繁雜一些)。假定我們要設計日志
記錄的類,支持記錄的方法有FileLog和EventLog兩種方式。在這里我們先不談設計模式,那么這個日志記錄的類就很好實現了: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
這樣的程序結構顯然不能符合我們的要求,假使我們增加一種新的日志記錄的方式DatabaseLog,那就要修改Log類,隨著記錄方式的變化,switch語句在不斷的變化,這樣就引起了整個應用程序的不穩定,進一步分析上面的代碼,發現對于EventLog和FileLog是兩種完全不同的記錄方式,它們之間不應當存在必然的聯系,而應當把它們分別作為單獨的對象來對待。1
///
2///EventLog類3///4publicclassEventLog5
{
6publicvoidWrite()7
{
8Console.WriteLine(\9}10}1112
///
13///FileLog類14///15publicclassFileLog16
{
17publicvoidWrite()18
{
19Console.WriteLine(\20}21}22
進一步抽象,為它們抽象出一個共同的父類,結構圖如下:
實現代碼:1
///
2///Log類3///
4publicabstractclassLog5
{
6publicabstractvoidWrite();7}8
此時EventLog和FileLog類的代碼應當如下: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的子類來實現,而無需再去修改EventLog和FileLog類,這樣的設計滿足了類之間的層次關系,又很好的符合了面向對象設計中的單一職責原則,每一個類都只負責一件具體的事情。到這里似乎我們的設計很完美了,事實上我們還沒有看客戶程序如何去調用。在應用程序中,我們要使用某一種日志記錄方式,可能會用到如下這樣的語句:
EventLogeventlog=newEventLog();eventlog.Write();
當日志記錄的方式從EventLog變化為FileLog,我們就得修改所有程序代碼中出現上面語句的部分,這樣的工作量是可想而知的。此時就需要解耦具體的日志記錄方式和應用程序。這就要引入FactoryMethod模式了,每一個日志記錄的對象就是工廠所生成的產品,既然有兩種記錄方式,那就需要兩個不同的工廠去生產了,代碼如下:1
///
2///EventFactory類3///
4publicclassEventFactory5
{
6publicEventLogCreate()7
{
8returnnewEventLog();9}10}11
///
12///FileFactory類13///14publicclassFileFactory15
{
16publicFileLogCreate()17
{
18returnnewFileLog();19}20}21
這兩個工廠和具體的產品之間是平行的結構,并一一對應,并在它們的基礎上抽象出一個公用的接口,結構圖如下:
實現代碼如下:1
///
2///LogFactory類3///
4publicabstractclassLogFactory5
{
6publicabstractLogCreate();7}8
此時兩個具體工廠的代碼應當如下:1
///
2///EventFactory類3///
4publicclassEventFactory:LogFactory5
{
6publicoverrideEventLogCreate()
7{
8returnnewEventLog();9}10}11
///
12///FileFactory類13///
14publicclassFileFactory:LogFactory15
{
16publicoverrideFileLogCreate()17
{
18returnnewFileLog();19}20}21
這樣通過工廠方法模式我們把上面那對象創立工作封裝在了工廠中,此時我們似乎完成了整個FactoryMethod的過程。這樣達到了我們應用程序和具體日志記錄對象之間解耦的目的了嗎?看一下此時客戶端程序代碼:1
///
2///App類
3///4publicclassApp5
{
6publicstaticvoidMain(string[]args)
7{
8LogFactoryfactory=newEventFactory();9
10Loglog=factory.Create();11
12log.Write();13}14}15
在客戶程序中,我們有效地避免了具體產品對象和應用程序之間的耦合,可是我們也看到,增加了具體工廠對象和應用程序之間的耦合。那這樣畢竟帶來什么好處呢?我們知道,在應用程序中,Log對象的創立是頻繁的,在這里我們可以把LogFactoryfactory=newEventFactory();
這句話放在一個類模塊中,任何需要用到Log對象的地方依舊不變。要是換一種日志記錄方式,只要修改一處為:
LogFactoryfactory=newFileFactory();
其余的任何地方我們都不需要去修改。有人會說那還是修改代碼,其實在開發中我們很難避免修改,但是我們可以盡量做到只修改一處。結構圖
適用性
在以下狀況下,適用于工廠方法模式:
1.當一個類不知道它所必需創立的對象的類的時候。2.當一個類希望由它的子類來指定它所創立的對象的時候。
3.當類將創立對象的職責委托給多個幫助子類中的某一個,并且你希望將哪一個幫助
子類是代理者這一信息局部化的時候。
生活中的例子
工廠方法定義一個用于創立對象的接口,但是讓子類決定實例化哪個類。壓注成型演示了這種模式。塑料玩具制造商加工塑料粉,將塑料注入到希望形狀的模具中。玩具的類別(車,人物等等)是由模具決定的。
例子抽象工廠(Creator)角色:是工廠方法模式的核心,與應用程序無關。任何在模式中創立的對象的工廠類必需實現這個接口。具體工廠(ConcreteCreator)角色:這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的規律,并且受到應用程序調用以創立產品對象。在上圖中有兩個這樣的角色:BulbCreator與TubeCreator。抽象產品(Product)角色:工廠方法模式所創立的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。在上圖中,這個角色是Light。具體產品(ConcreteProduct)角色:這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創立,它們之間往往一一對應。程序舉例: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();}}工廠方法的活動序列圖
活動過程包括:客戶端創立BulbCreator對象,客戶端持有此對象的類型是Creator,而實際類型是BulbCreator。然后客戶端調用BulbCreator的factory方法,之后BulbCreator調用BulbLight的構造函數創造出產品BulbLight對象。實現要點
1.FactoryMethod模式的兩種狀況:一是Creator類是一個抽象類且它不提供它所聲明的工廠方法的實現;二是Creator是一個具體的類且它提供一個工廠方法的缺省實現。
2.工廠方法是可以帶參數的。
3.工廠的作用并不僅僅只是創立一個對象,它還可以做對象的初始化,參數的設置等。效果
1.用工廠方法在一個類的內部創立對象尋常比直接創立對象更靈活。
2.FactoryMethod模式通過面向對象的手法,將所要創立的具體對象的創立工作延
遲到了子類,從而提供了一種擴展的策略,較好的解決了這種緊耦合的關系。總結
FactoryMethod模式是設計模式中應用最為廣泛的模式,通過本文,相信讀者已經對它有了一定的認識。然而我們要明確的是:在面向對象的編程中,對象的創立工作十分簡單,對象的創立時機卻很重要。FactoryMethod要解決的就是對象的創立時機問題,它提供了一種擴展的策略,很好地符合了開放封閉原則。
當發現系統只用一個產品類等級不足以描述所有的產品類,包括以后可能要添加的新的產品類時,就應當考慮采用工廠方法模式。由于工廠方法模式可以容大量個實的工廠類,以每一個工廠類負責每一個產品類等級,因此這種模式可以容納所有的產品等級。
區別:
關于工廠方法的一點探討,我們知道工廠方法屬于類型創立模式,而抽象工廠屬于對象創立模式,并且所謂的類創立模式就是把創立工作延遲到子類,而對象創立模式則將延遲到另一個對象。
工廠方法模式的意義是定義一個創立產品對象的工廠接口,將實際創立工作推遲到子類當中。核心工廠類不再負責產品的創立,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必需實現的接口
工廠解決的問題是一個系列的對象的創立;工廠方法模式在農場系統中的實現1背景
在簡單工廠模式中,有個全能的園丁,控制所有作物的種植、生長和收獲。現在農場規模變大了,管理更加專業化了。過去全能的園丁沒有了,每一種作物都有專門的園丁管理,形成了規模化和專業化生產。
2系統設計機構圖
3實現源碼
3.1水果產品接口Fruit.java
packagecom.lavasoft.patterns.factorymethod.ybms;/**
*CreatedbyIntelliJIDEA.*FileName:Fruit.java*ReadMe:水果接口*/
publicinterfaceFruit{/***種植*/
voidplant();/***生長*/
voidgrow();/***收獲
*/
voidharvest();}
3.2具體產品蘋果Apple.java
packagecom.lavasoft.patterns.factorymethod.ybms;/**
*CreatedbyIntelliJIDEA.*FileName:Apple.java*ReadMe:水果工廠的產品:蘋果*/
publicclassAppleimplementsFruit{privateinttreeAge;/***種植*/
publicvoidplant(){
System.out.println(\}/***生長*/
publicvoidgrow(){
System.out.println(\}
/***收獲*/
publicvoidharvest(){
System.out.println(\}/**
*@return返回樹齡*/
publicintgetTreeAge(){returntreeAge;}/***設置樹齡*/
publicvoidsetTreeAge(inttreeAge){this.treeAge=treeAge;}}
3.3具體產品葡萄:Grape.java
packagecom.lavasoft.patterns.factorymethod.ybms;/**
*CreatedbyIntelliJIDEA.*FileName:Grape.java*ReadMe:水果工廠的產品:葡萄
*/
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具體產品草莓:Strawberry.java
packagecom.lavasoft.patterns.factorymethod.ybms;/**
*CreatedbyIntelliJIDEA.*FileName:Strawberry.java*ReadMe:水果工廠的產品:草莓*/
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
*工廠模式--工廠方法模式--一般性模式(農場應用)*ReadMe:蘋果工廠方法*/
publicclassAppleGardenerimplementsFruitGardener{/**
*工廠方法*
*@return蘋果*/
publicFruitfactory(){Fruitf=newApple();
System.out.println(\水果工廠(AppletGardener)成功創立一個水果:蘋果!\returnf;}}
3.7葡萄工廠:GrapeGardener.java
packagecom.lavasoft.patterns.factorymethod.ybms;/**
*CreatedbyIntelliJIDEA.*FileName:GrapeGardener.java
*工廠模式--工廠方法模式--一般性模式(農場應用)*ReadMe:添加說明*/
publicclassGrapeGardenerimplementsFruitGardener{/***工廠方法*
*@return葡萄*/
publicFruitfactory(){Fruitf=newGrape();
System.out.println(\水果工廠(GrapeGardener)成功創立一個水果:葡萄!\returnf;}}
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 怎樣制定2025年工作銷售方案
- 2025年國慶節創意活動策劃方案
- 2025年元旦團日活動方案
- 直腸癌的護理查房
- 高績效主管的素養與技能
- 室內裝修結構設計
- CATIA初級班培訓教材(運動分析)1224
- 私立華聯學院《陰影透視》2023-2024學年第一學期期末試卷
- 溫州醫科大學《西方音樂史與作品欣賞(一)》2023-2024學年第二學期期末試卷
- 重慶工商大學《遙感地學分析》2023-2024學年第二學期期末試卷
- T-CTSS 86-2024 原味茶飲料標準
- 南航社會招聘筆試題目
- 燃料電池汽車講解
- DL∕T 5161.17-2018 電氣裝置安裝工程質量檢驗及評定規程 第17部分:電氣照明裝置施工質量檢驗
- 金蟬養殖注意事項及常見病蟲害防治
- SL-T+62-2020水工建筑物水泥灌漿施工技術規范
- 外掛懸挑式花籃盤扣腳手架安全專項施工方案7.17
- CJT 120-2016 給水涂塑復合鋼管
- 盧氏結構全文
- 2024年03月交通運輸部東海航海保障中心2024年度公開招考108名工作人員筆試歷年典型題及考點剖析附帶答案含詳解
- 裝配式混凝土結構施工重點難點分析及對策
評論
0/150
提交評論