版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
c#23種設計模式ChinaDocument4Colors節(jié)工期Howareyou完成日期12節(jié)創(chuàng)建型模式12.1單件模式(SingletonPattern)動機(Motivation):在軟件系統(tǒng)中,經常有這樣ー些特殊的類,必須保證它們在系統(tǒng)中只存在ー個實例,才能確保它們的邏輯正確性、以及良好的效率。如何繞過常規(guī)的構造器,提供ー?種機制來保證?個類只創(chuàng)建一個實例?這應該是類設計者的責任,而不是類使用者的責任.結構圖:加munynce加munynce二staticInstanceO0"■SingletonOperatk>n()GetSingletonDataOstaticuniqueinstancesingletonDaia意圖:保證ー個類僅有一個實例,并提供ー個訪問它的全局訪問點。<<設計模式>>GOF生活的例子:返回唯一實例返回唯一實例適用性:(1)當類只能有一個實例而且客戶可以從ー個眾所周知的訪問點訪問它時。(2)當這個唯一實例應該是通過子類化可擴展的,并且客戶應該無需更改代碼就能使用ー個
擴展的實例時。代碼實現(xiàn):(1)單線程Singleton實現(xiàn)classSingleThread_Singleton{privatestaticSingleThread_Singletoninstance=null;privateSingleThread_Singleton(){}publicstaticSingleThread_SingletonInstance(get(if(instance==null)(instance=newSingleThread_Singleton();)returninstance;)以上代碼在單線程情況下不會出現(xiàn)任何問題。但是在多線程的情況下卻不是安全的。如兩個線程同時運行到if(instance==nuH)判斷是否被實例化,ー個線程判斷為True后,在進行創(chuàng)建instance=newSingleThread_Singleton();之前,另ー個線程也判斷(instance==null),結果也為True.這樣就就違背了Singleton模式的原則(保證ー個類僅有一個實例)。怎樣在多線程情況下實現(xiàn)Singleton?(2)多線程Singleton實現(xiàn):classMultiThread_Singleton{privatestaticvolatileMultiThread_Singletoninstance=null;privatestaticobjectlockHelper=newobject();
privateMultiThread_Singleton(){}publicstaticMultiThread_Singleton InstanceTOC\o"1-5"\h\z{get{if(instance==null){lock(lockHelper){if (instance = = null){instance=newMultiThread_Singleton();)})return instance;)\o"CurrentDocument")此程序對多線程是安全的,使用了一個輔助對象lockHelper,保證只有一個線程創(chuàng)建實例(如果instance為空,保證只有一個線程instance=newMultiThread_Singleton();創(chuàng)建唯一的ー個實例)。(DoubleCheck)請注意ー個關鍵字volatile,如果去掉這個關鍵字,還是有可能發(fā)生線程不是安全的。volatile保證嚴格意義的多線程編譯器在代碼編譯時對指令不進行微調。(3)靜態(tài)Singleton實現(xiàn)classStatic_Singleton{publicstaticreadonlyStatic_Singletoninstance=newStatic_Singleton();privateStatic_Singleton(){}以上代碼展開等同于classStatic_SingletonTOC\o"1-5"\h\z{publicstaticreadonlyStatic_Singletoninstance;staticStatic_Singleton(){instance=newStatic_Singleton();)privateStatic_Singleton(){})由此可以看出,完全符合Singleton的原則。優(yōu)點:簡潔,易懂缺點:不可以實現(xiàn)帶參數(shù)實例的創(chuàng)建122抽象工程模式(AbstractFactory)常規(guī)的對象創(chuàng)建方法:〃創(chuàng)建一個Road對象Roadroad=newRoad();new的問題:實現(xiàn)依賴,不能應對“具體實例化類型”的變化。解決思路:封裝變化點——哪里變化,封裝哪里潛臺詞:如果沒有變化,當然不需要額外的封裝!工廠模式的緣起變化點在“對象創(chuàng)建”,因此就封裝“對象創(chuàng)建”面向接口編程ーー依賴接口,而非依賴實現(xiàn)最簡單的解決方法:classRoadFactory{publicstaticRoadCreateRoad(){returnnewRoad();
))〃創(chuàng)建一個Road對象Roadroad=roadFactory.CreateRoad();創(chuàng)建一系列相互依賴對象的創(chuàng)建工作:假設ー個游戲開場景:我們需要構造"道路"、"房屋"、"地道","從林"…等等對象工廠方法如下:classRoadFactoryTOC\o"1-5"\h\z(publicstaticRoadCreateRoad()(returnnewRoad();)publicstaticBuildingCreateBuilding(){returnnewBuilding();)publicstaticTunnel CreateTunnel(){returnnewTunnel();)publicstaticJungle CreateJungle(){returnnewJungle();)}調用方式如下:1Roadroad=RoadFactory.CreateRoad();Buildingbuilding=RoadFactory.CreateBuilding();Tunneltunnel=RoadFactory.CreateTunnel();Junglejungle=RoadFactory.CreateJungle();如上可見簡單工廠的問題:不能應對"不同系列對象"的變化。比如有不同風格的場景一ー對應不同風格的道路,房屋、地
道,…如何解決:使用面向對象的技術來"封裝"變化點O動機(Motivate):在軟件系統(tǒng)中,經常面臨著"ー系統(tǒng)相互依賴的對象"的創(chuàng)建工作;同時,由于需求的變化,往往存在更多系列對象的創(chuàng)建工作。如何應對這種變化?如何繞過常規(guī)的對象創(chuàng)建方法(new),提供?種"封裝機制"來避免客戶程序和這種"多系列具體對象創(chuàng)建工作"的緊耦合?意圖(Intent):提供ー個創(chuàng)建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。 《設計模式》G0F結構圖(Struct):適用性:.一個系統(tǒng)要獨立于它的產品的創(chuàng)建、組合和表示時。.ー個系統(tǒng)要由多個產品系統(tǒng)中的一個來配置時。.當你要強調?系列相關的產品對象的設計以便進行聯(lián)合使用時。.當你提供ー個產品類庫,而只想顯示它們的接口不是實現(xiàn)時。生活例子:?戶,慢??ベッ?沖爾?得”ホ?件。結構圖代碼實現(xiàn):abstractclassAbstractFactoryTOC\o"1-5"\h\z(publicabstractAbstractProductACreateProductA();publicabstractAbstractProductsCreateProductB();)abstractclassAbstractProductA{publicabstractvoidInteract(AbstractProductBb);)abstractclassAbstractProductB(publicabstractvoidInteract(AbstractProductAa);)classClient{privateAbstractProductAAbstractProductA;4 privateAbstractProductBAbstractProductB;678910111213141512345678910111234567891011AbstractProductA=factory.CreateProductA();AbstractProducts=factory.CreateProductB();)publicvoidRun()(AbstractProducts.Interact(AbstractProductA);AbstractProductA.Interact(AbstractProducts);})classConcreteFactory1:AbstractFactory(publicoverrideAbstractProductACreateProductA()(returnnewProductAI();}publicoverrideAbstractProductsCreateProductB()(returnnewProductBI();)}classConcreteFactory2:AbstractFactory(publicoverrideAbstractProductACreateProductA()(returnnewProdcutA2();)publicoverrideAbstractProductsCreateProductB()(returnnewProductB2();)}1classProductA1:AbstractProductApublicoverridevoidInteract(AbstractProductBb)TOC\o"1-5"\h\z{Console.WriteLine(this.GetType().Name+Minteractwith"+b.GetType().Name);))classProductBI:AbstractProductB{publicoverridevoidlnteract(AbstractProductAa){Console.WriteLine(this.GetType().Name+"interactwith"+a.GetType().Name);)}classProdcutA2:AbstractProductA(publicoverridevoidInteract(AbstractProductBb){Console.WriteLine(this.GetType().Name+"interactwith"+b.GetType().Name);)]classProductB2:AbstractProductB(publicoverridevoidInteract(AbstractProductAa){Console.WriteLine(this.GetType().Name+"interactwith"+a.GetType().Name);))publicstaticvoidMain()(//AbstractfactorylAbstractFactoryfactoryl=newConcreteFactoryl();
Clientc1= new Client(factory1);c1.Run();〃Abstractfactory2AbstractFactory factory2=newConcreteFactory2();Clientc2= new Client(factory2);c2.Run();}AbstractFactory注意的幾點:如果不存在”多系列對象創(chuàng)建"的需求變化,則沒必要應用AbstractFactory模式,靜態(tài)工廠方法足矣。"系列對象”指的是這些對象之間有相互依賴、或作用的關系。例如游戲開發(fā)場景中的"道路"與"房屋"依賴,“道路"與‘地道"的依賴。AbstractFactory模式主要在于應對”新系歹『的需求變動。其缺點在于難以應對"新對象”的需求變動。AbstractFactory模式經常和FactoryMethod模式共同組合來應對“對象創(chuàng)建”的需求變化.3建造者模式(Builder)Builder模式的緣起:假設創(chuàng)建游戲中的ー個房屋House設施,該房屋的構建由兒部分組成,且各個部分富于變化。如果使用最直觀的設計方法,每ー個房屋部分的變化,都將導致房屋構建的重新修正…一動機(Motivation):在軟件系統(tǒng)中,有時候面臨ー個“復雜對象”的創(chuàng)建工作,其通常由各個部分的子對象用一定辦法構成;由ア需求的變化,這個復雜対象的各個部分經常面臨著劇烈的變化,但是將它們組合到ー起的算法卻相對穩(wěn)定。如何應對種變化呢?如何提供?種"封裝機制"來隔離出"復雜對象的各個部分"的變化,從而保持系統(tǒng)中的"穩(wěn)定構建算法"不隨需求的改變而改變?意圖(Intent):將一個復雜對象的構建ワ其表示相分離,使得同樣的構建過程可以創(chuàng)建不同的表示。 《設計模式》GOF結構圖(Struct):DirectorBuilder+Construct()-BuildPart()FetchIteminStructurebuild.BuildPart()ConcreteBuilder*BuildPart()*GctRcsult()aDirectoraConcreteBuilderaDirectoraConcreteBuilder協(xié)作(Collaborations):aClient生活中的例子:newDireclorfaConcreteBuikJer)ConstructOBuildPadAOInewConcreteButldefBuikJPadBOBuiklParlCoGetResultOMX MM適用性:.當創(chuàng)建復雜對象的算法應該獨立于該對象的組成部分以及它們的裝配方式時。.當構造過程必須允許被構造的對象有不同的表示時。實例代碼:Builder類:publicabstractclassBuilder{public abstract void BuildDoor();public abstract void BuildWall();public abstract void BuildWindows();public abstract void BuildFloor();public abstract void BuildHouseCeilingO;publicabstractHouseGetHouse();)Director類:這一部分是組合到?起的算法(相對穩(wěn)定)。publicclassDirector{publicvoidConstruct(Builderbuilder)(builder.BuildWall();builder.BuildHouseCeilingO;builder.BuildDoor();builder.BuildWindows();builder.BuildFloor();TOC\o"1-5"\h\z))ChineseBuilder類publicclassChineseBuilder:Builder{privateHouseChineseHouse=newHouse();publicoverridevoidBuildDoor()Console.WriteLine("thisDoor*sstyleofChinese");TOC\o"1-5"\h\z)publicoverride voidBuildWall(){Console.WriteLine("thisWall'sstyleofChinese',);)publicoverride voidBuildWindows(){Console.WriteLine("thisWindows*sstyleofChinese");)publicoverride void BuildFloor(){Console.WriteLine("thisFloor*sstyleofChinese");}publicoverride void BuildHouseCeiling(){Console.WriteLine("thisCeiling*sstyleofChinese");)publicoverrideHouseGetHouse(){returnChineseHouse;))RomanBuilder類:classRomanBuilder:Builder{privateHouseRomanHouse=newHouse();publicoverride void BuildDoor(){Console.WriteLine("thisDoor*sstyleofRoman");}publicoverride void BuildWall()(Console.WriteLine("thisWall*sstyleofRoman");
publicoverridevoidBuildWindows()TOC\o"1-5"\h\z{Console.WriteLine("thisWindows'sstyleofRoman");)publicoverride void BuildFloor(){Console.WriteLine("thisFloor,sstyleofRoman");)publicoverride void BuildHouseCeiling(){Console.WriteLine("thisCeiling'sstyleofRoman");)publicoverrideHouseGetHouse(){returnRomanHouse;))ChineseBuilderfllRomanBuilder這兩個是:這個復雜對象的兩個部分經常面臨著劇烈的變化。publicclassClient{publicstaticvoidMain(string[]args)(Directordirector=newDirector();Builderinstance;Console.WriteLine("PleaseEnterHouseNo:");stringNo=Console.ReadLine();stringhouseType=ConfigurationSettings.AppSettings["No"+No];
15instance=(Builder)Assembly.Load('*House").Createlnstance(MHouse.*'+houseType);151617 director.Construct(instance);18Househouse=instance.GetHouse();house.Show();21Console.ReadLine();))<?xmlversion="1.0"encoding="utf-8"?><configuration><appSettings><addkey=**No1"value="RomanBuilder"></add><addkey="No2"value=MChineseBuilder"></add></appSettings></configuration>Builder模式的幾個要點:Builder模式主要用于“分步驟構建一個復雜的對象”。在這其中“分步驟”是ー個穩(wěn)定的乘法,而復雜對象的各個部分則經常變化。Builder模式主要在于應對“復雜對象各個部分”的頻繁需求變動。其缺點在于難以應對“分步驟構建算法”的需求變動。AbstractFactory模式解決“系列對象”的需求變化,Builder模式解決“對象部分”的需求變化。Builder械通常和Composite模式組合使用124工廠方法模式(FactoryMethod)耦合關系:
耦合關系直接決定著軟件面對變化時的行為-模塊與模塊之間的緊耦合使得軟件面對變化時,相關的模塊都要隨之更改-模塊與模塊之間的松耦合使得軟件面對變化時,一些模塊更容易被替換或者更改,但其他模塊保持不變動機(Motivation):在軟件系統(tǒng)中,由于需求的變化,"這個對象的具體實現(xiàn)"經常面臨著劇烈的變化,但它卻有比較穩(wěn)定的接口。如何應對這種變化呢?提供ー種封裝機制來隔離出"這個易變對象"的變化,從而保持系統(tǒng)中"其它依賴的對象"不隨需求的變化而變化。意圖(Intent):定義ー個用戶創(chuàng)建對象的接口,讓子類決定實例哪ー個類。FactoryMethod使ー個類的實例化延遲到子類。 《設計模式》GOF生活實例:結構圖(Struct):
生活實例:玩具馬模具適用性:.當一個類不知道它所必須創(chuàng)建的對象類的時候。.當ー個類希望由它子類來指定它所創(chuàng)建對象的時候。.當類將創(chuàng)建對象的職責委托給多個幫助子類中的某個,并且你希望將哪ー個幫助子類是代理者這一信息局部化的時候。實例代碼:CarFactory類:publicabstractclassCarFactoryTOC\o"1-5"\h\z(publicabstractCarCarCreate();)Car類:publicabstractclassCar(publicabstractvoidStartUp();publicabstractvoidRun();publicabstractvoidStop();]HongQiCarFactory類:1publicclassHongQiCarFactory:CarFactory
publicoverrideCarCarCreate()TOC\o"1-5"\h\z{returnnewHongQiCar();))BMWCarFactory類:publicclassBMWCarFactory:CarFactory(public overrideCarCarCreate(){returnnewBMWCar();))HongQiCar類:publicclassHongQiCar:Car{public override void StartUp()(Console.WriteLine("TestHongQiCarstart-upspeed!");)public override void Run(){Console.WriteLine("TheHongQiCarrunisveryquickly!");)publicoverridevoidStop(){Console.WriteLine("Theslowstoptimeis3second");))BMWCar類:publicclassBMWCar:Car{publicoverridevoidStartUpOConsole.WriteLine(MTheBMWCarstart-upspeedisveryquickly");TOC\o"1-5"\h\z)publicoverridevoid Run(){Console.WriteLine("TheBMWCarrunisquitelyfastandsafe!!!**);)publicoverridevoidStop(){Console.WriteLine("Theslowstoptimeis2second");))app.config1<?xmlversion="1.0"encoding="utf-8"?><configuration><appSettings><addkey="No1"value="HongQiCarFactory"/>oddkey="No2"value="BMWCarFactory"/></appSettings></configuration>Program類:1classProgram3staticvoidMain(string[]args)5Console.WriteLine("PleaseEnterFactoryMethodNo:");6 Console.WriteLine("*…………);7 Console.WriteLine("no FactoryMethod");Console.WriteLine("1 HongQiCarFactory");9 Console.WriteLine("2 BMWCarFactorゾ);10 Console.WriteLine("*…………);11 intno=lnt32.Parse(Console.ReadLine().ToString());12 stringfactoryType=ConfigurationManager.AppSettings["No"+no];13 //CarFactoryfactory=newHongQiCarFactory();14 CarFactoryfactory=(CarFactory)Assembly.Load("FactoryMehtod").Cr
eatelnstance(HFactoryMehtod."+factoryType);;Carcar=factory.CarCreate();car.StartUp();car.Run();car.Stopf);)}FactoryMethod模式的幾個要點:FactoryMethod模式主要用于隔離類對象的使用者和貝體類型之間的耦合關系。面對ー個經常變化的具體類型,緊耦合關系會導致軟件的脆弱。FactoryMethod模式通過面向對象的手法,將所要創(chuàng)建的R體對象工作延遲到子類,從而實現(xiàn)ー種擴展(而非更改)的策略,較好地解決了這種緊耦合關系。FactoryMehtod模式解決’‘單個對象”的需求變化,AbstractFactory模式解決’‘系歹リ對象''的需求變化,Builder模式解決“對象部分”的需求變化125原型模式(Prototype)依賴關系倒置:抽象不應該依賴于實現(xiàn)細節(jié),實現(xiàn)細節(jié)應該依賴于抽象。抽象不應該依賴于實現(xiàn)細節(jié),實現(xiàn)細節(jié)應該依賴于抽象。?抽象A直接依賴于實現(xiàn)細節(jié)bー抽象A依賴于抽象?抽象A直接依賴于實現(xiàn)細節(jié)bー抽象A依賴于抽象B,實現(xiàn)細節(jié)b依賴于抽象B實現(xiàn)細節(jié)b抽象A抽象B實現(xiàn)細節(jié)b動機(Motivate):在軟件系統(tǒng)中,經常面臨著“某些結構復雜的對象’的創(chuàng)建工作;由于需求的變化,這些對象經常面臨著劇烈的變化,但是它們卻擁有比較穩(wěn)定一致的接口。如何應對這種變化?如何向“客戶程序(使用這些對象的程序)"隔離出“這些易變對象”,從而使得“依賴這些易變對象的客戶程序”不隨著需求改變而改變?意圖(Intent):用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。 《設計模式》GOF結構圖(Struct):生活例子:適用性:.當一個系統(tǒng)應該獨立于它的產品創(chuàng)建,構成和表示時;
.當要實例化的類是在運行時刻指定時,例如,通過動態(tài)裝載;.為了避免創(chuàng)建一個與產品類層次平行的工廠類層次時:.當ー個類的實例只能有幾個不同狀態(tài)組合中的ー種時。建立相應數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實例化該類更方便一些。示意性代碼例子:publicabstractclassNormalActorTOC\o"1-5"\h\z{publicabstractNormalActorclone();)publicclassNormalActorA:NormalActor(publicoverrideNormalActorclone(){Console.WriteLine("NormalActorAiscall");return(NormalActor)this.MemberwiseClone();})publicclassNormalActorB:NormalActor(publicoverrideNormalActorclone(){Console.WriteLine("NormalActorBwascalled");return(NormalActor)this.MemberwiseClone();))publicclassGameSystem
publicvoidRun(NormalActornormalActor)NormalActornormalActorl=normalActor.clone();NormalActornormalActor2=normalActor.cione();NormalActornormalActor3=normalActor.clone();NormalActornormalActor4=normalActor.clone();NormalActornormalActor5=normalActor.clone();)}classProgram(staticvoidMain(string[]args)(GameSystemgameSystem=newGameSystem();gameSystem.Run(newNormalActorA());))如果又需要創(chuàng)建新的對象(flyActor),只需創(chuàng)建此抽象類,然后具體類進行克隆。publicabstractclassFlyActor(publicabstractFlyActorclone();}publicclassFlyActorB:FlyActor(///<summary>//Z淺拷貝,如果用深拷貝,可使用序列化///</summary>〃/<returns></returns>publicoverrideFlyActorclone()return(FlyActor)this.MemberwiseClone();))此時,調用的Main。函數(shù)只需如下:classProgram(staticvoidMain(string[]args)(GameSystemgameSystem=newGameSystem();gameSystem.Run(newNormalActorA(),newFlyActorB());})Prototype的兒個要點:Prototype模式同樣用于隔離類對象的使用者和具體類型(易變類)之間的耦合關系,它同樣要求這些“易變類”擁有“穩(wěn)定的接口”。Prototype模式對于“如何創(chuàng)建易變類的實體對象“采用“原型克隆”的方法來做,它使得我們可以非常靈活地動態(tài)創(chuàng)建“擁有某些穩(wěn)定接口中”的新對象ーー一所需工作僅僅是注冊的地方不斷地Clone.Prototype模式中的Clone方法可以利用.net中的object類的memberwiseClone。方法或者序列化來實現(xiàn)深拷貝。有關創(chuàng)建型模式的討論:Singleton模式解決的是實體對象個數(shù)的問題。除了Singleton之外,其他創(chuàng)建型模式解決的是都是new所帶來的耦合關系。
FactoryMethod,AbstractFactory,Builder都需要一個額外的工廠類來負責實例化“易變對象”,而Prototype則是通過原型(ー個特殊的工廠類)來克隆“易變對象”。如果遇到“易變類”,起初的設計通常從FactoryMehtod開始,當遇到更多的復雜變化時,再考慮重重構為其他三種エ廠模式(AbstractFactory,Builder,Prototype)適配器模式(AdapterPattern)適配(轉換)的概念無處不在 適配,即在不改變原有實現(xiàn)的基礎上,將原先不兼容的接口轉換為兼容的接U。例如:二轉換為三箱插頭,將高電壓轉換為低電壓等。動機(Motivate):在軟件系統(tǒng)中,由于應用環(huán)境的變化,常常需要將“一些現(xiàn)存的對象”放在新的環(huán)境中應用,但是新環(huán)境要求的接口是這些現(xiàn)存對象所不滿足的。那么如何應對這種“遷移的變化”?如何既能利用現(xiàn)有對象的良好實現(xiàn),同時乂能滿足新的應用環(huán)境所要求的接口?這就是本文要說的Adapter模式。意圖(Intent):將一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以ー起工作?!对O計模式》G0F結構(Struct):
圖1:對象適配器?Interface?闇2:類適配器生活中的例子:1/2,陽槽適配器圖1:對象適配器?Interface?闇2:類適配器生活中的例子:1/2,陽槽適配器孔1/4‘陰槽1/2I陰槽1/4,陽槽適用性:.系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要。
.想要建立一個可以重復使用的類,用于與一些彼此之間沒有太大關聯(lián)的ー些類,包括ー些可能在將來引進的類ー起工作。這些源類不一定有很復雜的接口。.(對對象適配器而言)在設計里,需要改變多個已有子類的接口,如果使用類的適配器模式,就要針對每一個子類做ー個適配器,而這不太實際。示意性代碼實例:interfaceIStack{voidPush(object item);voidPop();objectPeek();)〃對象適配器(Adapter與Adaptee組合的關系)publicclassAdapter:IStack〃適配對象(ArrayListadaptee;〃被適配的對象publicAdapter()TOC\o"1-5"\h\z(adaptee=newArrayList();)publicvoid Push(objectitem){adaptee.Add(item);)publicvoidPop(){adaptee.RemoveAt(adaptee.Count-1);)publicobjectPeek(){returnadaptee[adaptee.Count-1];))類適配器
publicclassAdapter:ArrayList,IStack{public void Push(objectitem)TOC\o"1-5"\h\z{this.Add(item);)public void Pop(){this.RemoveAt(this.Count-1);)publicobjectPeek(){returnthis[this.Count-1];))Adapter模式的兒個要點:Adapter模式主要應用于“希望復用ー些現(xiàn)存的類,但是接口又與復用環(huán)境要求不一致的情況”,在遺留代碼復用、類庫遷移等方面非常有用。GOF23定義了兩種Adapter模式的實現(xiàn)結構:對象適配器和類適配器。但類適配器采用“多繼承”的實現(xiàn)方式,帶來不良的高耦合,所以一般不推薦使用。對象適配器采用“對象組合”的方式,更符合松耦合精神。Adapter模式可以實現(xiàn)的非常靈活,不必拘泥于GOF23中定義的兩種結構。例如,完全可以將Adapter模式中的“現(xiàn)存對象”作為新的接口方法參數(shù),來達到適配的目的。Adapter模式本身要求我們盡可能地使用”面向接口的編程"風格,這樣才能在后期很方便的適配..NET框架中的Adapter應用:(1)在.Net中復用com對象:Com對象不符合.net對象的接口使用tlbimp.exe來創(chuàng)建一個RuntimeCallableWrapper(RCW)以使其符合.net對象的接口。(2).NET數(shù)據(jù)訪問類(Adapter變體):各種數(shù)據(jù)庫并沒有提供DataSet接口使用DBDataAdapter可以將任何各數(shù)據(jù)庫訪問/存取適配到ー?個DataSet對象上。(3)集合類中對現(xiàn)有對象的排序(Adapter變體);
現(xiàn)有對象未實現(xiàn)【Comparable接口實現(xiàn)ー個排序適配器(繼承【Comparer接口),然后在其Compare方法中對兩個對象進行比較。橋接模式(BridgePattern)動機(Motivate):在軟件系統(tǒng)中,某些類型由于自身的邏輯,它具有兩個或多個維度的變化,那么如何應對這種“多維度的變化”?如何利用面向對象的技術來使得該類型能夠輕松的沿著多個方向進行變化,而又不引入額外的復雜度?意圖(Intent):將抽象部分與實現(xiàn)部分分離,使它們都可以獨立的變化。 《設計模式》GOF結構圖(Struct):生活中的例子:我想大家小時候都有用蠟筆畫畫的經歷吧。紅紅綠綠的蠟筆一大盒,根據(jù)想象描繪出格式圖樣。而毛筆下的國畫更是工筆寫意,各展風采。而今天我們的故事從蠟筆與毛筆說起。設想要繪制一幅圖畫,藍天、白云、綠樹、小鳥,如果畫面尺寸很大,那么用蠟筆繪制就會遇到點麻煩。畢竟細細的蠟筆要涂出一片藍天,是有些麻煩。如果有可能,最好有套大號蠟筆,粗粗的蠟筆很快能涂抹完成。至于色彩嗎,最好每種顏色來支粗的,除了藍天還有綠地呢。這樣,
如果ー套12種顏色的蠟筆,我們需要兩套24支,同種顏色的一粗一細。呵呵,畫還沒畫,開始做夢了:要是再有一套中號蠟筆就更好了,這樣,不多不少總共36支蠟筆。再看看毛筆這ー邊,居然如此簡陋:ー套水彩12色,外加大中小三支毛筆。你可別小瞧這"簡陋”的組合,畫藍天用大毛筆,畫小鳥用小毛筆,各具特色。呵呵,您是不是已經看出來了,不錯,我今天要說的就是Bridge模式。為了一幅畫,我們需要準備36支型號不同的蟒筆,而改用毛筆三支就夠了,當然還要搭配上12種顏料。通過Bridge模式,我們把乘法運算3,12=36改為了加法運算3+12=15,這ー改進可不小。那么我們這里蠟筆和毛筆到底有什么區(qū)別呢?實際上,蠟筆和毛筆的關鍵ー個區(qū)別就在于筆和顏色是否能夠分離。[GOF95】橋梁模式的用意是"將抽象化(Abstraction)與實現(xiàn)化(Impiementation)脫耦,使得二者可以獨立地變化"?關鍵就在于能否脫耦。蠟筆的顏色和蠟筆本身是分不開的,所以就造成必須使用36支色彩、大小各異的蠟筆來繪制圖畫。而毛筆與顏料能夠很好的脫耦,各自獨立變化,便簡化了操作。在這里,抽象層面的概念是:"毛筆用顏料作畫",而在實現(xiàn)時,毛筆有大中小三號,顏料有紅綠藍等12種,于是便可出現(xiàn)3x12種組合。每個參與者(毛筆與顏料)都可以在自己的自由度上隨意轉換。
蠟筆由于無法將筆與顏色分離,造成筆與顏色兩個自由度無法單獨變化,使得只有創(chuàng)建36種對象才能完成任務。Bridge模式將繼承關系轉換為組合關系,從而降低了系統(tǒng)間的耦合,減少了代碼編寫量。代碼實現(xiàn):abstractclassBrush(protectedColorc;publicabstractvoid Paint();publicvoidSetColor(Colorc){this.c=c;}TOC\o"1-5"\h\z}classBigBrush:Brush(publicoverridevoidPaint(){Console.WriteLine(MUsingbigbrushandcolor{0}painting**,c.color);})classSmallBrush:Brush{publicoverridevoidPaint(){Console.WriteLine(nUsingsmallbrushandcolor{0}painting",c.color);})classColor(publicstringcolor;)
publicRed(){this.color="red";})classGreen:Color(publicGreen(){this.color="green";})classBlue:Color(publicBlue(){this.color="blue";})classProgram{publicstaticvoidMain()(Brushb=newBigBrush();b.SetColor(newRed());b.Paint();b.SetColor(newBlue());b.Paint();b.SetColor(newGreen());b.Paint();b=newSmallBrush();b.SetColor(newRed());b.Paint();b.SetColor(newBlue());b.Paint();3451234512345123456789101112131415161718b.SetColor(newGreen());b.Paint();)適用性:.如果一個系統(tǒng)需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態(tài)的聯(lián)系。.設計要求實現(xiàn)化角色的任何改變不應當影響客戶端,或者說實現(xiàn)化角色的改變對客戶端是完全透明的。.ー個構件有多于ー個的抽象化角色和實現(xiàn)化角色,系統(tǒng)需要它們之間進行動態(tài)耦合。.雖然在系統(tǒng)中使用繼承是沒有問題的,但是由于抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。Bridge要點:1.Bridge模式使用“對象間的組合關系”解耦了抽象和實現(xiàn)之間固有的綁定關系,使得抽象和實現(xiàn)可以沿著各自的維度來變化。所謂抽象和實現(xiàn)沿著各自維度的變化,即“子類化”它們,得到各個子類之后,便可以任意它們,從而獲得不同平臺上的不同型號。Bridge模式有時候類似于多繼承方案,但是多繼承方案往往違背了類的單ー職責原則(即ー個類只有一個變化的原因),復用性比較差。Bridge模式是比多繼承方案更好的解決方法。Bridge模式的應用一般在“兩個非常強的變化維度”,有時候即使有兩個變化的維度,但是某個方向的變化維度并不劇烈——換言之兩個變化不會導致縱橫交錯的結果,并不一定要使用Bridge模式。裝飾模式(DecoratorPattern)子類復子類,子類何其多假如我們需要為游戲中開發(fā)ー種坦克,除了各種不同型號的坦克外,我們還希望在不同場合中為其増加以下ー種或多種功能;比如紅外線夜視功能,比如水陸兩棲功能,比如衛(wèi)星定位功能等等。按類繼承的作法如下:〃抽象坦克publicabstractclassTankpublicabstractvoidShot();publicabstractvoidRun();TOC\o"1-5"\h\z)各種型號://T50型號publicclassT50:Tank(publicoverride void Shot()(Console.WriteLine("T50坦克平均每秒射擊5發(fā)子弾”);)publicoverride void Run(){Console.WriteLine("T50垣克平均每時運行30公里”);)}//T75型號publicclassT75:Tank{publicoverride void Shot()(Console.WriteLine("T75坦克平均每秒射擊10發(fā)子弾");)publicoverride void Run()(Console.WriteLine("T75垣克平均每時運行35公里");}}1//T90型號2publicclassT90:Tankpublic override void Shot()TOC\o"1-5"\h\z{Console.WriteLine("T90坦克平均每秒射擊10發(fā)子彈つ;]public override void Run()(Console.WriteLine("T90坦克平均每時運行40公里”);)}各種不同功能的組合:比如IA具有紅外功能接ロ、IB具有水陸兩棲功能接ロ、IC具有衛(wèi)星定位功能接口。//T50坦克各種功能的組合publicclassT50A:T50,lA{〃具有紅外功能)publicclassT50B:T50,lB{〃具有水陸兩棲功能)publicclassT50C:T50,IC{)publicclassT50AB:T50,IA,IB{)18publicclassT50AC:T50,lA,IC{)publicclassT50BC:T50,IB,IC{)publicclassT50ABC:T50,IA,IB,IC123456789101112131415161718192021222324252627282930123//T75各種不同型號坦克各種功能的組合publicclassT75A:T75,IA〃具有紅外功能)publicclassT75B:T75JB(〃具有水陸兩棲功能)publicclassT75C:T75,IC{〃具有衛(wèi)星定位功能}publicclassT75AB:T75,IA,IB(〃具有紅外、水陸兩棲功能publicclassT75AC:T75,IA,IC(〃具有紅外、衛(wèi)星定位功能publicclassT75BC:T75,IB,IC{〃具有水陸兩棲、衛(wèi)星定位功能publicclassT75ABC:T75JA,IBJC{〃具有紅外、水陸兩棲、衛(wèi)星定位功能//T90各種不同型號坦克各種功能的組合publicclassT90A:T90JA
{〃具有紅外功能)publicclassT90B:T90,IB{〃具有水陸兩棲功能)publicclassT90C:T90,IC{〃具有衛(wèi)星定位功能14)15publicclassT90AB:T90,IA,IB16(1?〃具有紅外、水陸兩棲功能18}19publicclassT90AC:T90,lA,IC20{21〃具有紅外、衛(wèi)星定位功能22)23publicclassT90BC:T90,IB,IC24{25〃具有水陸兩棲、衛(wèi)星定位功能26}27publicclassT90ABC:T90,IA,IB,IC28{〃具有紅外、水陸兩棲、衛(wèi)星定位功能)由此可見,如果用類繼承實現(xiàn),子類會爆炸式地增長。動機(Motivate):上述描述的問題根源在于我們“過度地使用了繼承來擴展對象的功能”,由于繼承為類型引入的靜態(tài)物質,使得這種擴展方式缺乏靈活性;并且隨著子類的増多(擴展功能的增多),各種子類的組合(擴展功能組合)會導致更多子類的膨脹(多繼承)。如何使“對象功能的擴展”能夠根據(jù)需要來動態(tài)地實現(xiàn)?同時避免"擴展功能
的增多”帶來的子類膨脹問題?從而使得任何“功能擴展變化”所導致的影響將為最低?意圖(Intent):動態(tài)地給ー個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成『類更《設計模式》GOF《設計模式》GOF結構圖(Struct):生活中的例子:適用性:需要擴展一個類的功能,或給ー個類增加附加責任。需要動態(tài)地給ー個対象增加功能,這些功能可以再動態(tài)地撤銷。需要增加由一些基本功能的排列組合而產生的非常大量的功能,從而使繼承關系變得不現(xiàn)實。實現(xiàn)代碼:namespaceDecorator(publicabstractclassTank{publicabstractvoidShot();publicabstractvoidRun();})namespaceDecorator{publicclassT50:TankTOC\o"1-5"\h\z{public overridevoidShot(){Console.WriteLine("T50坦克平均每秒射擊5發(fā)子彈つ;)public overridevoidRun(){Console.WriteLine("T50坦克平均每時運行30公里”);))namespaceDecorator{publicclassT75:TankTOC\o"1-5"\h\z{publicoverride voidShot(){Console.WriteLine("T75坦克平均每秒射擊10發(fā)子彈つ;)publicoverride voidRun(){Console.WriteLine("T75坦克平均每時運行35公里”);}}}namespaceDecorator{publicclassT90:TankTOC\o"1-5"\h\z{publicoverridevoidShot(){Console.WriteLine("T90坦克平均每秒射擊10發(fā)子彈つ;}publicoverride voidRun(){Console.WriteLine("T90坦克平均每時運行40公里”);)))1namespaceDecorator2(3publicabstractclassDecorator:Tank//DoAs接11繼承非實現(xiàn)繼承TOC\o"1-5"\h\z{privateTanktank;//Hasa對象組合public Decorator(Tanktank){this.tank=tank;)public override void Shot(){tank.Shot();)public override void Run(){tank.Run();)))namespaceDecorator{publicclassDecoratorA:DecoratorTOC\o"1-5"\h\z{publicDecoratorA(Tanktank):base(tank){)publicoverridevoidShot(){//Dosomeextension〃功能擴展且有紅外功能base.Shot();)publicoverridevoidRun(){base.Run();)))namespaceDecorator{publicclassDecoratorB:DecoratorTOC\o"1-5"\h\z(publicDecoratorB(Tanktank):base(tank)()publicoverridevoidShot(){//Dosomeextension〃功能擴展且有水陸兩棲功能base.Shot();)publicoverridevoidRun(){base.Run();)))namespaceDecorator{publicclassDecoratorC:DecoratorTOC\o"1-5"\h\z4 {publicDecoratorC(Tanktank):base(tank)(}publicoverridevoidShot()
TOC\o"1-5"\h\z{//Dosomeextension〃功能擴展且有衛(wèi)星定位功能base.Shot();)publicoverridevoidRun(){base.Run();)))classProgram{staticvoidMain(string[]args)(Tanktank=new T50();DecoratorAda = newDecoratorA(tank);〃且有紅外功能DecoratorBdb = newDecoratorB(da); 〃且有纟「外和水陸兩棲功能DecoratorCde = newDecoratorC(db); 〃且有紅外、水陸兩棲、衛(wèi)星定們三種功能dc.Shot();dc.Run();})Decorator模式的兒個要點:通過采用組合、而非繼承的手法,Decorator模式實現(xiàn)了在運行時動態(tài)地擴展對象功能的能力,而且可以根據(jù)需要擴展多個功能。避免了單獨使用繼承帶來的“靈活性差”和“多子類衍生問題\Component類在Decorator模式中充當抽象接口的角色,不應該去實現(xiàn)具體的行為。而且Decorator類對于Component類應該透明--?換ざ之Component類無需知道Decorator類,Decorator類是從外部來擴展Component類的功能。Decorator類在接口上表現(xiàn)為is-aComponent的繼承關系,即Decorator類繼承了Component類所且有的接口。但在實現(xiàn)上又表現(xiàn)hasaComponent的組合關系,B|JDecorator類又使用了另外一個Component類。我們可以使用ー個或者多個Decorator對象來“裝飾”?個Component對象,且裝飾后的對象仍然是?個Component對象。Decorator模式并非解決"多子類衍生的多繼承“問題,Decorator模式應用的要點在于解決“主體類在多個方向上的擴展功能”……是為“裝飾”的含義。Decorator在.NET(Stream)中的應用:可以看到,BufferedStream和CryptoStream其實就是兩個包裝類,這里的Decorator模式省略了抽象裝飾角色(Decorator),示例代碼如下:classProgram(publicstaticvoidMain(string[]args)(Memorystreamms=newMemoryStream(newbyte[]{100,456,864,222,567));2234567891011121314151213〃擴展了緩沖的功能17BufferedStreambuff=newBufferedStream(ms);18192021 〃擴展了緩沖,加密的功能2223CryptoStreamcrypto=newCryptoStream(buff);2425 )2627)通過反編譯,可以看到BufferedStream類的代碼(只列出部分),它是繼承于Stream類:1publicsealedclassBufferedStream:Stream//MethodsprivateBufferedStream();publicBufferedStream(Streamstream);publicBufferedStream(Streamstream,intbufferSize);//Fieldsprivateint_bufferSize;
privateStream_s;)組合模式(CompositePattern)動機(Motivate):組合模式有時候又叫做部分一整體模式,它使我們樹型結構的問題中,模糊了簡單元素和復雜元素的概念,客戶程序可以向處理簡單元素一樣來處理復雜元素,從而使得客戶程序與復雜元素的內部結構解耦。意圖(Intenり:將對象組合成樹形結構以表示“部分一整體”的層次結構。Composite模式使得用戶對單個對象和組合對象的使用具有一致性。 《設計模式》GOF結構圖(Strucり:生活中的例子:
適用性:.你想表示對象的部分一整體層次結構.你希望用戶忽略組合對象與單個對象的不同,用戶將統(tǒng)一地使用組合結構中的所有對象。代碼實現(xiàn):這里我們用繪圖這個例子來說明Composite模式,通過ー些基本圖像元素(直線、圓等)以及ー些復合圖像元素(由基本圖像元素組合而成)構建復雜的圖形樹。在設計中我們對每ー個對象都配備ー個Draw。方法,在調用時,會顯示相關的圖形??梢钥吹剑@里復合圖像元素它在充當對象的同時,又是那些基本圖像元素的?個容器。先看?下基本的類結構圖:圖中橙色的區(qū)域表示的是復合圖像元素。示意性代碼:publicabstractclassGraphics{protectedstring_name;
publicGraphics(stringname){this._name=name;)publicabstractvoidDraw();)publicclassPicture:Graphics{publicPicture(stringname):base(name)TOC\o"1-5"\h\z{)1,7 publicoverridevoidDraw(){//)publicArrayListGetChilds(){〃返回所有的子對象))而其他作為樹枝構件,實現(xiàn)代碼如下:publicclassLine:Graphics(publicLine(stringname):base(name){)publicoverridevoidDraw(){Console.WriteLine("Drawa"+_name.ToString());
12publicclassCircle:Graphics{publicCircle(stringname):base(name)TOC\o"1-5"\h\z{}publicoverridevoidDraw(){Console.WriteLine("Drawa"+_name.ToString());))publicclassRectangle:Graphics{publicRectangle(stringname):base(name)TOC\o"1-5"\h\z{)publicoverridevoidDraw(){Console.WriteLine("Drawa"+_name.ToString());))現(xiàn)在我們要對該圖像元素進行處理:在客戶端程序中,需要判斷返回對象的具體類型到底是基本圖像元素,還是復合圖像元素。如果是復合圖像元素,我們將要用遞歸去處理,然而這種處理的結果卻增加了客戶端程序與復雜圖像元素內部結構之間的依賴,那么我們如何去解耦這種關系呢?我們希望的是客戶程序可以像處理基木闇像元素一樣來處理復合闇像元素,這就要引入Composite模式了,需要把對于子對象的管理工作交給復合圖像元素,為了進行子對象的管理,它必須提供必要的Add(),Remove。等方法,類結構圖如下:
示意代碼:publicabstractclassGraphics{protectedstring_name;publicGraphics(stringname){this._name=name;)publicabstractvoidDraw();publicabstractvoidAdd();publicabstractvoidRemove();}publicclassPicture:Graphics15{protectedArrayListpicList=newArrayList();publicPicture(stringname):base(name){}publicoverridevoidDraw()
Console.WriteLine("Drawa"+_name.ToString());foreach(GraphicsginpicList)(g.Draw();})publicoverridevoidAdd(Graphicsg)(picList.Add(g);)publicoverridevoidRemove(Graphicsg)(picList.Remove(g);}}publicclassLine:Graphics{publicLine(stringname):base(name)()publicoverridevoidDraw(){Console.WriteLine(MDrawa"+_name.ToString());}publicoverridevoidAdd(Graphicsg)(}publicoverridevoidRemove(Graphicsg)23242526272829303132333435363738394041424344454647484950515253545556{}57585960616263646566676869707172737475767778798081828384858687publicclassCircle:Graphics(publicCircle(stringname):base(name)(}publicoverridevoidDraw()(Console.WriteLine("Drawa"+_name.ToString());)publicoverridevoidAdd(Graphicsg)()publicoverridevoidRemove(Graphicsg){)}publicclassRectangle:GraphicsIpublicRectangle(stringname):base(name)()publicoverridevoidDraw(){Console.WriteLine(HDrawa"+_name.ToString());}publicoverridevoidAdd(Graphicsg)()publicoverridevoidRemove(Graphicsg)()}這樣引入Composite模式后,客戶端程序不再依賴于復合圖像元素的內部實現(xiàn)了。然而,我們程序中仍然存在著問題,因為Line,Rectangle,Circle已經沒有了「對象,它是?個基本圖像元素,因此Add(),Remove。的方法對于它來說沒有任何意義,而且把這種錯誤不會
在編譯的時候報錯,把錯誤放在了運行期,我們希望能夠捕獲到這類錯誤,并加以處理,稍微改進一下我們的程序:1publicclassLine:Graphics2(publicLine(stringname):base(name)TOC\o"1-5"\h\z{)publicoverridevoidDraw(){Console.WriteLine("Drawa"+_name.ToString());}publicoverridevoidAdd(Graphicsg){〃拋出ー個我們自定義的異常)publicoverridevoidRemove(Graphicsg){〃拋出ー個我們自定義的異常))這樣改進以后,我們可以捕獲可能出現(xiàn)的錯誤,做進ー步的處理。上面的這種實現(xiàn)方法屬于透明式的Composite模式,如果我們想要更安全的--種做法,就需要把管理子對象的方法聲明在樹枝構件Pictu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 廣告定向技術行業(yè)經營分析報告
- 奶酪制造機產品供應鏈分析
- 醫(yī)用生物堿產業(yè)鏈招商引資的調研報告
- 2024年哈爾濱巴彥縣交通運輸局選調事業(yè)單位工作人員5人筆試模擬試題及答案解析
- 2024內蒙古京海煤矸石發(fā)電有限責任公司招聘筆試模擬試題及答案解析
- 開展班級興趣小組的思考計劃
- 學校專兼職咨詢師工作制度與考核辦法
- 社團成員之間的溝通協(xié)調計劃
- 決策過程中數(shù)據(jù)的有效利用計劃
- 2-2章運算放大器
- 2022年甬統(tǒng)表全套
- 人教版(B版2019課標)高中數(shù)學選擇性必修一2.7.1拋物線的標準方程 學案
- 國開電大《工程數(shù)學(本)》形成性考核作業(yè)1-4輔導資料
- 原油電脫水處理技術(行業(yè)知識)
- 政策智能匹配與精準推送服務平臺項目方案
- 園林空間教學課件
- 我的中國心課件PPT課件
- 發(fā)展經濟學-馬春文主編-課后習題答案
- 同濟大學教學質量保障體系
- 湘價服200981國家規(guī)范最新版
- 土地復墾方案編制規(guī)程第1部分通則
評論
0/150
提交評論