你的位置:首页 > ASP.net教程

[ASP.net教程]七、创建型模式之建造者、原型、单例


一、建造者模式

    将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

    指挥者这个类用来控制建造过程,也用来隔离用户与建造过程的关联。

   Builder:人

   ConcreteBuilder1:胖子

   ConcreteBuilder2:瘦子

   Director:开始组装

   Product:成果

  

image

//具体产品类,最终形成的产品样式 class Product  {    //产品的组成部分的集合    IList<string> parts = new List<string>();    //增加部件    public void Add(string part)    {      parts.Add(part);    }        //列举所有的产品部件    public void Show()    {      Console.WriteLine("\n产品 创建 ----");      foreach (string part in parts)      {        Console.WriteLine(part);      }    }  }

//抽象建造者类,确定有几个部件,并返回产品abstract class Builder  {    //两个部件组成    public abstract void BuildPartA();    public abstract void BuildPartB();    public abstract Product GetResult();  }  //产品A实现类  class ConcreteBuilder1 : Builder  {    private Product product = new Product();        //将部件A组装到产品上    public override void BuildPartA()    {      product.Add("部件A");    }    //将部件B组装到产品上    public override void BuildPartB()    {      product.Add("部件B");    }    public override Product GetResult()    {      return product;    }  }  //产品B实现类  class ConcreteBuilder2 : Builder  {    private Product product = new Product();    public override void BuildPartA()    {      product.Add("部件X");    }    public override void BuildPartB()    {      product.Add("部件Y");    }    public override Product GetResult()    {      return product;    }  }

//指挥者类 class Director  {    public void Construct(Builder builder)    {      //创建部件A      builder.BuildPartA();      //创建部件B      builder.BuildPartB();    }  }

//客户端代码static void Main(string[] args)    {      //初始化一个指挥者      Director director = new Director();      //初始化两个具体产品类      Builder b1 = new ConcreteBuilder1();     Builder b2 = new ConcreteBuilder2();      //创建产品A     director.Construct(b1);      //获得最终产品      Product p1 = b1.GetResult();      p1.Show();      //创建产品B     director.Construct(b2);      //获得最终产品      Product p2 = b2.GetResult();      p2.Show();      Console.Read();    }

二、原型模式

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

    原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

    一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这样既隐藏了对象创建的细节,又对性能是大大的提高,不用重新初始化对象,而是动态地获得对象运行时的状态。

image

//抽象原型类abstract class Prototype  {    private string id;    // 构造函数
    public Prototype(string id)    {      this.id = id;    }    // 属性     public string Id    {      get { return id; }    }        public abstract Prototype Clone();  }  //具体原型类1  class ConcretePrototype1 : Prototype  {    public ConcretePrototype1(string id): base(id)    {    }    //创建当前对象的浅表副本    public override Prototype Clone()    {      return (Prototype)this.MemberwiseClone();    }  }  //也可以通过实现NET提供的ICloneable接口来取代抽象类  class ConcretePrototype2 : ICloneable  {    
    private string id;    // 构造函数
    public ConcretePrototype2 (string id)    {      this.id = id;    }
    public string Id 
    { 
get { return id; } 
    }
    public Object Clone()    {      return (Object)this.MemberwiseClone();    }  }

//客户端代码 static void Main(string[] args)    {      //创建p1      ConcretePrototype1 p1 = new ConcretePrototype1("I");      //复制给c1      ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();      Console.WriteLine("Cloned: {0}", c1.Id);      ConcretePrototype2 p2 = new ConcretePrototype2("II");      ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();      Console.WriteLine("Cloned: {0}", c2.Id);      // Wait for user       Console.Read();    }

浅表复制(MemberwiseClone()):如果字段是值类型的,则对该字段执行逐位复制;如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。如果需要深复制,需要在复制方法中编写程序,把任何形式类型转换成值类型再复制一次。

三、单例模式

    保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显式定义的构造方法,默认的构造方法就会失效,将构造方法的修饰符改为private,则外部程序就不能用new来实例化它了。

    优势:让类自身复制保持它的唯一实例。这个类可以保证没有其他实例可以被创建,并且还提供了一个访问该实例的方法(对唯一的实例可以严格地控制用户怎样及何时访问它)。

image

//Singleton类class Singleton  {    private static Singleton instance;    private static readonly object syncRoot = new object();    //修改构造方法修饰符,使外界不能利用new创建实例    private Singleton()    {    }    //创建实例    public static Singleton GetInstance()    {      //双重锁定,先判断实例是否存在,不存在再加锁处理      if (instance == null)      {        //不存在,则加线程锁,防止其他线程在前一个线程没有执行完的时候再次创建        lock (syncRoot)        {          if (instance == null)          {            //初始化实例            instance = new Singleton();          }        }      }      return instance;    }  }

//客户端代码 static void Main(string[] args)    {      //用此方法初始化实例  
      Singleton s1 = Singleton.GetInstance();
      //由于s1已经创建了实例,则s2不会再次创建新实例
      Singleton s2 = Singleton.GetInstance();      if (s1 == s2)      {        Console.WriteLine("Objects are the same instance");      }      Console.Read();    }

PS:lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

四、衍生

    静态初始化:c#与公共语言运行库提供了一种“静态初始化”方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决多线程环境下它是不安全的问题。

    饿汉式单例类:静态初始化的方式是在自己被加载时就将自己实例化。一般已经足够使用

    懒汉式单例类:在第一次被引用时,才会将自己实例化。

//增加sealed修饰符,阻止发生派生,而派生可能会增加实例public sealed class Singleton  {    //在第一次引用类的任何成员时创建实例    private static readonly Singleton instance = new Singleton();    private Singleton() { }    public static Singleton GetInstance()    {      return instance;    }  }