创建型模式总结

来源:互联网 发布:淘宝导航栏字体加粗 编辑:程序博客网 时间:2024/06/05 18:34

创建型模式总结

创建型模式列表 Abstract Factory  Creates an instance of several families of classes  Builder  Separates object construction from its representation  Factory Method  Creates an instance of several derived classes  Prototype  A fully initialized instance to be copied or cloned  Singleton

  A class of which only a single instance can exist

创建型模式,就是用来创建对象的模式,抽象了实例化的过程。它帮助一个系统独立于如何创建、组合和表示它的那些对象。本文主要对前面几章五种常用创建型模式进行了比较,通过一个游戏开发场景的例子来说该如何使用创建型模式。

一、为什么需要创建型模式

所有的创建型模式都有两个永恒的主旋律:第一,它们都将系统使用哪些具体类的信息封装起来;第二,它们隐藏了这些类的实例是如何被创建和组织的。外界对于这些对象只知道它们共同的接口,而不清楚其具体的实现细节。正因如此,创建型模式在创建什么(what),由谁(who)来创建,以及何时(when)创建这些方面,都为软件设计者提供了尽可能大的灵活性。

假定在一个游戏开发场景中,会用到一个现代风格房屋的对象,按照我们的一般想法,既然需要对象就创建一个:

ModernRoom room = new ModernRoom();

好了,现在现代风格房屋的对象已经有了,如果这时房屋的风格变化了,需要的是古典风格的房屋,修改一下:

ClassicalRoom room = new ClassicalRoom();

试想一下,在我们的程序中有多少处地方用到了这样的创建逻辑,而这里仅仅是房屋的风格变化了,就需要修改程序中所有的这样的语句。现在我们封装对象创建的逻辑,把对象的创建放在一个工厂方法中:

ModernFactory factory = new ModernFactory();

ModernRoom room = factory.Create();

当房屋的风格变化时,只需要修改

ClassicalFactory factory = new ClassicalFactory();

ClassicalRoom room = factory.Create();

而其它的用到room的地方仍然不变。这就是为什么需要创建型模式了。创建者模式作用可以概括为如下两点:

1.封装创建逻辑,绝不仅仅是new一个对象那么简单。

2.封装创建逻辑变化,客户代码尽量不修改,或尽量少修改。

二、常见的五种创建型模式

单件模式(Singleton Pattern)解决的是实体对象的个数问题,其他的都是解决new所带来的耦合关系问题。

工厂方法模式(Factory Pattern)在工厂方法中,工厂类成为了抽象类,其实际的创建工作将由其具体子类来完成。工厂方法的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中去,强调的是“单个对象”的变化。

抽象工厂模式(Abstract Factory)抽象工厂是所有工厂模式中最为抽象和最具有一般性的一种形态。抽象工厂可以向客户提供一个接口,使得客户可以在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象,强调的是“系列对象”的变化。

生成器模式(Builder Pattern)把构造对象实例的逻辑移到了类的外部,在这个类的外部定义了这个类的构造逻辑。他把一个复杂对象的构造过程从对象的表示中分离出来。其直接效果是将一个复杂的对象简化为一个比较简单的目标对象。他强调的是产品的构造过程。

原型模式(Prototype Pattern)和工厂模式一样,同样对客户隐藏了对象创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。

三、如何选择使用创建型模式

继续考虑上面提到的游戏开发场景,假定在这个游戏场景中我们使用到的有墙(Wall),屋子(Room),门(Door)几个部件。在这个过程中,同样是对象的创建问题,但是会根据所要解决的问题不同而使用不同的创建型模式。

如果在游戏中,一个屋子只允许有一个门存在,那么这就是一个使用Signleton模式的例子,确保只有一个Door类的实例被创建。解决的是对象创建个数的问题。

 

示例代码:

[c-sharp] view plaincopy
  1. using System;  
  2.   
  3. public sealed class SigletonDoor  
  4. {  
  5.     static readonly SigletonDoor instance=new SigletonDoor();  
  6.     static SigletonDoor()  
  7.     {  
  8.     }  
  9.     public static SigletonDoor Instance  
  10.     {  
  11.         get  
  12.         {  
  13.             return instance;  
  14.         }  
  15.     }  
  16. }  

在游戏中需要创建墙,屋子的实例时,为了避免直接对构造器的调用而实例化类,这时就是工厂方法模式了,每一个部件都有它自己的工厂类。解决的是“单个对象”的需求变化问题。

 

示例代码:

[c-sharp] view plaincopy
  1. using System;  
  2.   
  3. public abstract class Wall  
  4. {  
  5.     public abstract void Display();  
  6. }  
  7.   
  8. public class ModernWall:Wall  
  9. {  
  10.     public override void Display()  
  11.     {  
  12.         Console.WriteLine("ModernWall Builded");  
  13.     }  
  14. }  
  15.   
  16. public abstract class WallFactory  
  17. {  
  18.     public abstract Wall Create();  
  19. }  
  20.   
  21. public class ModernFactory:WallFactory  
  22. {  
  23.     public override Wall Create()  
  24.     {  
  25.         return new ModernWall();;  
  26.     }  
  27. }  
 

在游戏场景中,不可能只有一种墙或屋子,有可能有现代风格(Modern),古典风格(Classical)等多系列风格的部件。这时就是一系列对象的创建问题了,是一个抽象工厂的例子。解决的是“系列对象”的需求变化问题。 

示例代码:

[c-sharp] view plaincopy
  1. using System;  
  2. public abstract class Wall  
  3. {  
  4.     public abstract void Display();  
  5. }  
  6. public class ModernWall:Wall  
  7. {  
  8.     public override void Display()  
  9.     {  
  10.         Console.WriteLine("ModernWall Builded");  
  11.     }  
  12. }  
  13. public class ClassicalWall:Wall  
  14. {  
  15.     public override void Display()  
  16.     {  
  17.         Console.WriteLine("ClassicalWall Builded");  
  18.     }  
  19. }  
  20. public abstract class Room  
  21. {  
  22.     public abstract void Display();  
  23. }  
  24. public class ModernRoom:Room  
  25. {  
  26.     public override void Display()  
  27.     {  
  28.         Console.WriteLine("ModernRoom Builded");  
  29.     }  
  30. }  
  31. public class ClassicalRoom:Room  
  32. {  
  33.     public override void Display()  
  34.     {  
  35.         Console.WriteLine("ClassicalRoom Builded");  
  36.     }  
  37. }  
  38.   
  39. public abstract class AbstractFactory  
  40. {  
  41.     public abstract Wall CreateWall();  
  42.     public abstract Room CreateRoom();  
  43. }  
  44. public class ModernFactory:AbstractFactory  
  45. {  
  46.     public override Wall CreateWall()  
  47.     {  
  48.         return new ModernWall();  
  49.     }  
  50.     public override Room CreateRoom()  
  51.     {  
  52.         return new ModernRoom();  
  53.     }  
  54. }  
  55. public class ClassicalFactory:AbstractFactory  
  56. {  
  57.     public override Wall CreateWall()  
  58.     {  
  59.         return new ClassicalWall();  
  60.     }  
  61.     public override Room CreateRoom()  
  62.     {  
  63.         return new ClassicalRoom();  
  64.     }  
  65. }  

如果在游戏场景中,构成某一个场景的算法比较稳定,例如:这个场景就是用四堵墙,一个屋子,一扇门来构成的,但具体是用什么风格的墙、屋子和门则是不停的变化的,这就是一个生成器模式的例子。解决的是“对象部分”的需求变化问题。

示例代码:

[c-sharp] view plaincopy
  1. using System;  
  2.   
  3. using System.Collections;  
  4.   
  5.   
  6. public class Director  
  7.   
  8. {  
  9.   
  10.     public void Construct( Builder builder )  
  11.   
  12.     {  
  13.   
  14.         builder.BuildWall();  
  15.   
  16.         builder.BuildRoom();  
  17.   
  18.         builder.BuildDoor();  
  19.   
  20.     }  
  21.   
  22. }  
  23.   
  24.   
  25. public abstract class Builder  
  26.   
  27. {  
  28.   
  29.     public abstract void BuildWall();  
  30.   
  31.     public abstract void BuildRoom();  
  32.   
  33.     public abstract void BuildDoor();  
  34.   
  35.     public abstract GameScene GetResult();  
  36.   
  37. }  
  38.   
  39.   
  40. public class GameBuilder : Builder  
  41.   
  42. {  
  43.   
  44.     private GameScene g;  
  45.   
  46.   
  47.     public override void BuildWall()  
  48.   
  49.     {  
  50.   
  51.         g = new GameScene();  
  52.   
  53.         g.Add( "Wall" );  
  54.   
  55.     }  
  56.   
  57.     public override void BuildRoom()  
  58.   
  59.     {  
  60.   
  61.         g.Add( "Room" );  
  62.   
  63.     }  
  64.   
  65.     public override void BuildDoor()  
  66.   
  67.     {  
  68.   
  69.         g.Add( "Door" );  
  70.   
  71.     }  
  72.   
  73.     public override GameScene GetResult()  
  74.   
  75.     {  
  76.   
  77.         return g;  
  78.   
  79.     }  
  80.   
  81. }  
  82.   
  83.   
  84. public class GameScene  
  85.   
  86. {  
  87.   
  88.     ArrayList parts = new ArrayList();  
  89.   
  90.     public void Add( string part )  
  91.   
  92.     {  
  93.   
  94.         parts.Add( part );  
  95.   
  96.     }  
  97.   
  98.     public void Display()  
  99.   
  100.     {  
  101.   
  102.         Console.WriteLine( " GameScene Parts:" );  
  103.   
  104.         foreachstring part in parts )  
  105.   
  106.             Console.WriteLine( part );  
  107.   
  108.     }  
  109.   
  110. }  

如果在游戏中,需要大量的古典风格或现代风格的墙或屋子,这时可以通过拷贝一个已有的原型对象来生成新对象,就是一个原型模式的例子了。通过克隆来解决“易变对象”的创建问题。

 

示例代码:

[c-sharp] view plaincopy
  1. using System;  
  2.   
  3.   
  4. public abstract class RoomPrototype  
  5.   
  6. {  
  7.   
  8.     public abstract RoomPrototype Clone();  
  9.   
  10. }  
  11.   
  12.   
  13. public class ModernPrototype:RoomPrototype  
  14.   
  15. {  
  16.   
  17.     public override RoomPrototype Clone()  
  18.   
  19.     {  
  20.   
  21.         return (RoomPrototype)this.MemberwiseClone();  
  22.   
  23.     }  
  24.   
  25. }  
  26.   
  27.   
  28. public class ClassicalPrototype:RoomPrototype  
  29.   
  30. {  
  31.   
  32.     public override RoomPrototype Clone()  
  33.   
  34.     {  
  35.   
  36.         return (RoomPrototype)this.MemberwiseClone();  
  37.   
  38.     }  
  39.   
  40. }  

究竟选用哪一种模式最好取决于很多的因素。使用Abstract Factory、Prototype Pattern或Builder Pattern的设计比使用Factory Method的设计更加灵活,但是也更加复杂,尤其Abstract Factory需要庞大的工厂类来支持。通常,设计以使用Factory Method开始,并且当设计者发现需要更大的灵活性时,设计便会向其他设计模式演化,当你在多个设计模式之间进行权衡的时候,了解多个设计模式可以给你提供更多的选择余地。

附录:参考资料

1、创建型模式专题总结

2、创建型模式

3、创建型模式之间的比较