一、建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。
指挥者这个类用来控制建造过程,也用来隔离用户与建造过程的关联。
Builder:人
ConcreteBuilder1:胖子
ConcreteBuilder2:瘦子
Director:开始组装
Product:成果
//具体产品类,最终形成的产品样式 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(); }
二、原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这样既隐藏了对象创建的细节,又对性能是大大的提高,不用重新初始化对象,而是动态地获得对象运行时的状态。
//抽象原型类 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来实例化它了。
优势:让类自身复制保持它的唯一实例。这个类可以保证没有其他实例可以被创建,并且还提供了一个访问该实例的方法(对唯一的实例可以严格地控制用户怎样及何时访问它)。
//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; } }