资源描述
C# 23种设计模式 China Document 4 Colors1.1节 工期How are you1.1.1 完成日期1.2节 创建型模式1.2.1 单件模式(Singleton Pattern)动机(Motivation): 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。 如何绕过常规的构造器,提供一种机制来保证一个类只创建一个实例? 这应该是类设计者的责任,而不是类使用者的责任。结构图: 意图: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 -GOF生活的例子: 适用性: (1)当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。 (2)当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。代码实现:(1)单线程Singleton实现 classSingleThread_SingletonprivatestaticSingleThread_Singletoninstance=null;privateSingleThread_Singleton()publicstaticSingleThread_SingletonInstancegetif(instance=null)instance=newSingleThread_Singleton();returninstance;以上代码在单线程情况下不会出现任何问题。但是在多线程的情况下却不是安全的。如两个线程同时运行到 if(instance=null)判断是否被实例化,一个线程判断为True后,在进行创建instance=newSingleThread_Singleton();之前,另一个线程也判断(instance=null),结果也为True.这样就就违背了Singleton模式的原则(保证一个类仅有一个实例)。怎样在多线程情况下实现Singleton?(2)多线程Singleton实现:1classMultiThread_Singleton23privatestaticvolatileMultiThread_Singletoninstance=null;4privatestaticobjectlockHelper=newobject();5privateMultiThread_Singleton()6publicstaticMultiThread_SingletonInstance78get910if(instance=null)1112lock(lockHelper)1314if(instance=null)1516instance=newMultiThread_Singleton();17181920returninstance;212223 此程序对多线程是安全的,使用了一个辅助对象lockHelper,保证只有一个线程创建实例(如果instance为空,保证只有一个线程instance=newMultiThread_Singleton();创建唯一的一个实例)。(Double Check)请注意一个关键字volatile,如果去掉这个关键字,还是有可能发生线程不是安全的。volatile 保证严格意义的多线程编译器在代码编译时对指令不进行微调。(3)静态Singleton实现3classStatic_Singleton45 public staticreadonlyStatic_Singletoninstance=newStatic_Singleton();6privateStatic_Singleton()7以上代码展开等同于1classStatic_Singleton23 public staticreadonlyStatic_Singletoninstance;4staticStatic_Singleton()56instance=newStatic_Singleton();78privateStatic_Singleton()9由此可以看出,完全符合Singleton的原则。优点: 简洁,易懂缺点: 不可以实现带参数实例的创建1.2.2 抽象工程模式(Abstract Factory)常规的对象创建方法:/创建一个Road对象Roadroad=newRoad();new 的问题: 实现依赖,不能应对“具体实例化类型”的变化。解决思路: 封装变化点-哪里变化,封装哪里 潜台词: 如果没有变化,当然不需要额外的封装!工厂模式的缘起 变化点在“对象创建”,因此就封装“对象创建” 面向接口编程-依赖接口,而非依赖实现最简单的解决方法:1classRoadFactory2publicstaticRoadCreateRoad()34returnnewRoad();567/创建一个Road对象8Roadroad=roadFactory.CreateRoad();创建一系列相互依赖对象的创建工作:假设一个游戏开场景:我们需要构造道路、房屋、地道,从林.等等对象工厂方法如下:1classRoadFactory23publicstaticRoadCreateRoad()45returnnewRoad();67publicstaticBuildingCreateBuilding()89returnnewBuilding();1011publicstaticTunnelCreateTunnel()1213returnnewTunnel();1415publicstaticJungleCreateJungle()1617returnnewJungle();1819调用方式如下: 1Roadroad= RoadFactory.CreateRoad();3Buildingbuilding=RoadFactory.CreateBuilding();4Tunneltunnel=RoadFactory.CreateTunnel();5Junglejungle=RoadFactory.CreateJungle();如上可见简单工厂的问题: 不能应对不同系列对象的变化。比如有不同风格的场景-对应不同风格的道路,房屋、地道.如何解决: 使用面向对象的技术来封装变化点。动机(Motivate): 在软件系统中,经常面临着一系统相互依赖的对象的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作。 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和这种多系列具体对象创建工作的紧耦合?意图(Intent): 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 -设计模式GOF结构图(Struct): 适用性: 1.一个系统要独立于它的产品的创建、组合和表示时。 2.一个系统要由多个产品系统中的一个来配置时。 3.当你要强调一系列相关的产品对象的设计以便进行联合使用时。 4.当你提供一个产品类库,而只想显示它们的接口不是实现时。生活例子: 结构图代码实现:1abstractclassAbstractFactory23publicabstractAbstractProductACreateProductA();4publicabstractAbstractProductBCreateProductB();51abstractclassAbstractProductA23publicabstractvoidInteract(AbstractProductBb);41abstractclassAbstractProductB23publicabstractvoidInteract(AbstractProductAa);41classClient23privateAbstractProductAAbstractProductA;4privateAbstractProductBAbstractProductB;5publicClient(AbstractFactoryfactory)67AbstractProductA=factory.CreateProductA();8AbstractProductB=factory.CreateProductB();910publicvoidRun()1112AbstractProductB.Interact(AbstractProductA);13AbstractProductA.Interact(AbstractProductB);14151classConcreteFactory1:AbstractFactory23publicoverrideAbstractProductACreateProductA()45returnnewProductA1();67publicoverrideAbstractProductBCreateProductB()89returnnewProductB1();10111classConcreteFactory2:AbstractFactory23publicoverrideAbstractProductACreateProductA()45returnnewProdcutA2();67publicoverrideAbstractProductBCreateProductB()89returnnewProductB2();10111classProductA1:AbstractProductA23publicoverridevoidInteract(AbstractProductBb)45Console.WriteLine(this.GetType().Name+interactwith+b.GetType().Name);671classProductB1:AbstractProductB23publicoverridevoidInteract(AbstractProductAa)45Console.WriteLine(this.GetType().Name+interactwith+a.GetType().Name);671classProdcutA2:AbstractProductA23publicoverridevoidInteract(AbstractProductBb)45Console.WriteLine(this.GetType().Name+interactwith+b.GetType().Name);671classProductB2:AbstractProductB23publicoverridevoidInteract(AbstractProductAa)45Console.WriteLine(this.GetType().Name+interactwith+a.GetType().Name);671publicstaticvoidMain()23/Abstractfactory14AbstractFactoryfactory1=newConcreteFactory1();5Clientc1=newClient(factory1);6c1.Run();7/Abstractfactory28AbstractFactoryfactory2=newConcreteFactory2();9Clientc2=newClient(factory2);10c2.Run();11Abstract Factory注意的几点: 如果不存在”多系列对象创建“的需求变化,则没必要应用Abstract Factory模式,静态工厂方法足矣。 系列对象指的是这些对象之间有相互依赖、或作用的关系。例如游戏开发场景中的道路与房屋依赖,“道路”与“地道”的依赖。Abstract Factory模式主要在于应对新系列的需求变动。其缺点在于难以应对”新对象“的需求变动。Abstract Factory模式经常和Factory Method模式共同组合来应对“对象创建”的需求变化1.2.3 建造者模式(Builder)Builder模式的缘起: 假设创建游戏中的一个房屋House设施,该房屋的构建由几部分组成,且各个部分富于变化。如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正.动机(Motivation): 在软件系统中,有时候面临一个复杂对象的创建工作,其通常由各个部分的子对象用一定算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合到一起的算法却相对稳定。 如何应对种变化呢?如何提供一种封装机制来隔离出复杂对象的各个部分的变化,从而保持系统中的稳定构建算法不随需求的改变而改变?意图(Intent): 将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 -设计模式GOF结构图(Struct): 协作(Collaborations): 生活中的例子: 适用性: 1.当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。 2.当构造过程必须允许被构造的对象有不同的表示时。实例代码:Builder类:1publicabstractclassBuilder23publicabstractvoidBuildDoor();4publicabstractvoidBuildWall();5publicabstractvoidBuildWindows();6publicabstractvoidBuildFloor();7publicabstractvoidBuildHouseCeiling();89publicabstractHouseGetHouse();10Director类:这一部分是 组合到一起的算法(相对稳定)。 1publicclassDirector23publicvoidConstruct(Builderbuilder)45builder.BuildWall();6builder.BuildHouseCeiling();7builder.BuildDoor();8builder.BuildWindows();9builder.BuildFloor();1011ChineseBuilder类1publicclassChineseBuilder:Builder23privateHouseChineseHouse=newHouse();4publicoverridevoidBuildDoor()56Console.WriteLine(thisDoorsstyleofChinese);78publicoverridevoidBuildWall()910Console.WriteLine(thisWallsstyleofChinese);1112publicoverridevoidBuildWindows()1314Console.WriteLine(thisWindowssstyleofChinese);1516publicoverridevoidBuildFloor()1718Console.WriteLine(thisFloorsstyleofChinese);1920publicoverridevoidBuildHouseCeiling()2122Console.WriteLine(thisCeilingsstyleofChinese);2324publicoverrideHouseGetHouse()2526returnChineseHouse;2728RomanBuilder类:1classRomanBuilder:Builder23privateHouseRomanHouse=newHouse();4publicoverridevoidBuildDoor()56Console.WriteLine(thisDoorsstyleofRoman);78publicoverridevoidBuildWall()910Console.WriteLine(thisWallsstyleofRoman);1112publicoverridevoidBuildWindows()1314Console.WriteLine(thisWindowssstyleofRoman);1516publicoverridevoidBuildFloor()1718Console.WriteLine(thisFloorsstyleofRoman);1920publicoverridevoidBuildHouseCeiling()2122Console.WriteLine(thisCeilingsstyleofRoman);2324publicoverrideHouseGetHouse()2526returnRomanHouse;2728ChineseBuilder和RomanBuilder这两个是:这个复杂对象的两个部分经常面临着剧烈的变化。1publicclassClient23publicstaticvoidMain(stringargs)45Directordirector=newDirector();67Builderinstance;89Console.WriteLine(PleaseEnterHouseNo:);1011stringNo=Console.ReadLine();1213stringhouseType=ConfigurationSettings.AppSettingsNo+No;1415instance=(Builder)Assembly.Load(House).CreateInstance(House.+houseType);1617director.Construct(instance);1819Househouse=instance.GetHouse();20house.Show();2122Console.ReadLine();23241234567Builder模式的几个要点:Builder模式 主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的乘法,而复杂对象的各个部分则经常变化。Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。Abstract Factory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。Builder械通常和Composite模式组合使用1.2.4 工厂方法模式(Factory Method)耦合关系: 动机(Motivation): 在软件系统中,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但它却有比较稳定的接口。 如何应对这种变化呢?提供一种封装机制来隔离出这个易变对象的变化,从而保持系统中其它依赖的对象不随需求的变化而变化。意图(Intent): 定义一个用户创建对象的接口,让子类决定实例哪一个类。Factory Method使一个类的实例化延迟到子类。 -设计模式GOF结构图(Struct): 生活实例: 适用性: 1.当一个类不知道它所必须创建的对象类的时候。 2.当一个类希望由它子类来指定它所创建对象的时候。 3.当类将创建对象的职责委托给多个帮助子类中的某个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。实例代码:CarFactory类:1publicabstractclassCarFactory23publicabstractCarCarCreate();4Car类: 1publicabstractclassCar23publicabstractvoidStartUp();4publicabstractvoidRun();5publicabstractvoidStop();67HongQiCarFactory类:1publicclassHongQiCarFactory:CarFactory23publicoverrideCarCarCreate()45returnnewHongQiCar();67BMWCarFactory类:1publicclassBMWCarFactory:CarFactory23publicoverrideCarCarCreate()45returnnewBMWCar();67HongQiCar类:1publicclassHongQiCar:Car23publicoverridevoidStartUp()45Console.WriteLine(TestHongQiCarstart-upspeed!);67publicoverridevoidRun()89Console.WriteLine(TheHongQiCarrunisveryquickly!);1011publicoverridevoidStop()1213Console.WriteLine(Theslowstoptimeis3second);1415BMWCar类:1publicclassBMWCar:Car23publicoverridevoidStartUp()45Console.WriteLine(TheBMWCarstart-upspeedisveryquickly);67publicoverridevoidRun()89Console.WriteLine(TheBMWCarrunisquitelyfastandsafe!);1011publicoverridevoidStop()1213Console.WriteLine(Theslowstoptimeis2second);1415app.config1234567Program类:1classProgram23staticvoidMain(stringargs)45Console.WriteLine(PleaseEnterFactoryMethodNo:);6Console.WriteLine(*);7Console.WriteLine(noFactoryMethod);8Console.WriteLine(1HongQiCarFactory);9Console.WriteLine(2BMWCarFactory);10Console.WriteLine(*);11intno=Int32.Parse(Console.ReadLine().ToString();12stringfactoryType=ConfigurationManager.AppSettingsNo+no;13/CarFactoryfactory=newHongQiCarFactory();14CarFactoryfactory=(CarFactory)Assembly.Load(FactoryMehtod).CreateInstance(FactoryMehtod.+factoryType);15Carcar=factory.CarCreate();16car.StartUp();17car.Run();18car.Stop();192021Factory Method 模式的几个要点:Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。Factory Mehtod模式解决单个对象的需求变化,AbstractFactory模式解决系列对象的需求变化,Builder模式解决对象部分的需求变化1.2.5 原型模式(Prototype)依赖关系倒置: 动机(Motivate): 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。 如何应对这种变化?如何向“客户程序(使用这些对象的程序)隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?意图(Intent): 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 -设计模式GOF结构图(Struct): 生活例子: 适用性: 1当一个系统应该独立于它的产品创建,构成和表示时; 2当要实例化的类是在运行时刻指定时,例如,通过动态装载; 3为了避免创建一个与产品类层次平行的工厂类层次时; 4当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。 示意性代码例子:1publicabstractclassNormalActor23publicabstractNormalActorclone();41publicclassNormalActorA:NormalActor23publicoverrideNormalActorclone()45Console.WriteLine(NormalActorAiscall);6return(NormalActor)this.MemberwiseClone();7891publicclassNormalActorB:NormalActor23publicoverrideNormalActorclone()45Console.WriteLine(NormalActorBwascalled);6return(NormalActor)this.MemberwiseClone();789 public class GameSystem public void Run(NormalActor normalActor) NormalActor normalActor1 = normalActor.clone(); NormalActor normalActor2 = normalActor.clone(); NormalActor normalActor3 = normalActor.clone(); NormalActor normalActor4 = normalActor.clone(); NormalActor normalActor5 = normalActor.clone(); class Program static void Main(string args) GameSystem gameSystem = new GameSystem(); gameSystem.Run(new NormalActorA(); 如果又需要创建新的对象(flyActor),只需创建此抽象类,然后具体类进行克隆。 public abstract class FlyActor public abstract FlyActor clone(); public class FlyActorB:FlyActor / / 浅拷贝,如果用深拷贝,可使用序列化 / / public override FlyActor clone() return (FlyActor)this.MemberwiseClone(); 此时,调用的Main()函数只需如下: class Program static void Main(string args) GameSystem gameSystem = new GameSystem(); gameSystem.Run(new NormalActorA(), new FlyActorB(); Prototype的几个要点: Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。 Prototype模式对于“如何创建易变类的实体对象“采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口中”的新对象-所需工作仅仅是注册的地方不断地Clone. Prototype模式中的Clone方法可以利用.net中的object类的memberwiseClone()方法或者序列化来实现深拷贝。有关创建型模式的讨论: Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的是都是new 所带来的耦合关系。 Factory Method ,Abstract Factory,Builder都需要一个额外的工厂类来负责实例化“易变对象”,而Prototype则是通过原型(一个特殊的工厂类)来克隆“易变对象”。 如果遇到“易变类”,起初的设计通常从Factory Mehtod开始,当遇到更多的复杂变化时,再考虑重重构为其他三种工厂模式(Abstract Factory,Builder,Prototype)适配器模式(Adapter Pattern)适配(转换)的概念无处不在.适配,即在不改变原有实现的基础上,将原先不兼容的接口转换为兼容的接口。例如:二转换为三箱插头,将高电压转换为低电压等。 动机(Motivate): 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。 那么如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?这就是本文要说的Adapter 模式。意图(Intent): 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 -设计模式GOF结构(Struct): 图1:对象适配器
展开阅读全文