本文中尽量在一页中能够简单明了的说明各种常用创建类型的设计模式,尽量写的通俗易懂些(部分参照了其他地方的经典示例),其他类型设计模式将继续更新奉上。
细节很重要,以下设计模式代码中的类和方法中的修饰符个别省略掉使用类或者方法的默认修饰符,所以必须知道c#中默认的修饰符:类默认是internal,方法和嵌套类默认是private,构造函数显式声明的默认是private,否则系统帮忙生成的默认构造函数是public的;接口枚举成员默认是public且不能显式声明,结构属于值类型不能被继承,所以其内部成员是private的。
代码说明参照代码中的注释!
文章目录:
创建类型的模式
1)一般在应用中为了线程安全考虑,都会使用双重锁模式处理,如下代码:
//不推荐使用,这个反而是大多数教程里的示例 public sealed class Singleton { //私有静态变量 static Singleton instance=null; static readonly object padlock = new object(); //私有构造函数 Singleton() { } public static Singleton Instance { get { if (instance==null) { lock (padlock) { if (instance==null) { instance = new Singleton(); } } } return instance; } } }
2)以上实现不会确保在使用的时候再实例化(懒加载模式)且性能不佳,所以又有了以下实现:
//推荐使用,线程安全且实现懒加载 public sealed class Singleton { //私有构造函数,阻止自动生成的默认构造函数 Singleton() { } //提供全局访问出口 public static Singleton Instance { get { return Nested.instance; } } //嵌套类,实现懒加载 class Nested { //显示声明为静态构造函数(不能有修饰符,调用类中的成员或者第一次实例化时仅执行一次),确保了嵌套类实例化在调用之后,所以实现了懒加载,而且也保证了性能。 static Nested() { } //初始化后将不能改变 internal static readonly Singleton instance = new Singleton(); } }
2、工厂方法模式(定义一个接口或者抽象基类用于创建对象,但是让子类决定初始化哪个类。工厂方法把一个类的初始化下放到子类。)
工厂方法模式最大的有点就是利用面向对象的多态性,实现了对外开放访问,封闭修改的开发封闭原则。以下是示例
public abstract class Fruit { public abstract void Print(); } /// <summary> /// 苹果 /// </summary> public class Apple : Fruit { public override void Print() { Console.WriteLine("我是苹果!"); } } /// <summary> /// 香蕉 /// </summary> public class Banana : Fruit { public override void Print() { Console.WriteLine("我是香蕉"); } } /// <summary> /// 抽象工厂类 /// </summary> public abstract class FruitFactory { // 工厂方法 public abstract Fruit CreateFruit(); } /// <summary> /// 苹果的简单工厂类 /// </summary> public class AppleFactory : FruitFactory { public override Fruit CreateFruit() { return new Apple(); } } /// <summary> /// 香蕉的简单工厂类 /// </summary> public class BananaFactory : FruitFactory { public override Fruit CreateFruit() { return new Banana(); } } /// <summary> /// 客户端调用 /// </summary> class Client { static void Main(string[] args) { // 工厂初始化,妙处就在这里 工厂基类中的方法交由实现它的子类去处理创建的水果是苹果还是香蕉 FruitFactory _appleFactory = new AppleFactory(); FruitFactory _bananaFactory = new BananaFactory(); // 制作苹果,这个水果简单工厂做的是苹果 Fruit appleInsane = _appleFactory.CreateFruit(); appleInsane.Print(); //制作香蕉 ,这个水果简单工厂做的是香蕉 Fruit bananaInsane = _bananaFactory.CreateFruit(); bananaInsane.Print(); Console.Read(); } }
3、抽象工厂模式(为一个产品族提供了统一的创建接口。当需要这个产品族的某一系列的时候,可以从抽象工厂中选出相应的系列创建一个具体的工厂类。)
抽象工厂模式将具有同一主题特性的单独的工厂封装起来,它将一组对象的实现和使用分离开。比如以上的工厂方法模式中,一个水果简单工厂只能创建一个类的示例,不能创建一系列主题的类的实例,所以才有了抽象工厂模式来实现。以下是示例
//智能机接口 interface IDumb { string Name(); } //老式机接口 interface ISmart { string Name(); } //老式机产品类 class Asha : IDumb { public string Name() { return "Asha"; } } class Primo : IDumb { public string Name() { return "Guru"; } } //智能机产品 class Lumia : ISmart { public string Name() { return "Lumia"; } } class GalaxyS2 : ISmart { public string Name() { return "GalaxyS2"; } } /// <summary> /// 抽象工厂,跟IPhone没关系,只是个接口 /// </summary> interface IPhoneFactory { ISmart GetSmart(); IDumb GetDumb(); } //创建工厂类,例子 三星生产盖世智能机和primo老式机 class SamsungFactory : IPhoneFactory { public ISmart GetSmart() { return new GalaxyS2(); } public IDumb GetDumb() { return new Primo(); } } class NokiaFactory : IPhoneFactory { public ISmart GetSmart() { return new Lumia(); } public IDumb GetDumb() { return new Asha(); } } //客户端调用 static void Main(string[] args) { IPhoneFactory SAMSUNGfactory=new SamsungFactory(); Console.WriteLine("Smart Phone: " + SAMSUNGfactory.GetSmart().Name() + " Dumb Phone: " + SAMSUNGfactory.GetDumb().Name()); IPhoneFactory NOKIAfactory=new NokiaFactory(); Console.WriteLine("Smart Phone: " + NOKIAfactory.GetSmart().Name() + " Dumb Phone: " + NOKIAfactory.GetDumb().Name()); }
4、原型模式(用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。)
这个模式的就是利用克隆多个原型副本来创建对象,好处就是同样的对象实例不用总是new,节省内存
/// <summary> /// 原型 /// </summary> public abstract class Prototype { public string Id { get; set; } public Prototype(string id) { this.Id = id; } // 浅表克隆方法 public abstract Prototype Clone(); public abstract Prototype SClone(); } /// <summary> /// 创建具体原型 /// </summary> public class ConcretePrototype : Prototype { public ConcretePrototype(string id) : base(id) { } /// <summary> /// 浅拷贝 /// </summary> /// <returns></returns> public override Prototype Clone() { // 调用MemberwiseClone方法实现的是浅拷贝 return this.MemberwiseClone() as Prototype; } /// <summary> /// 深拷贝 /// </summary> /// <returns></returns> public override Prototype SClone() { MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, this); stream.Position = 0; return formatter.Deserialize(stream) as Prototype; } } //客户端调用 class Client { static void Main(string[] args) { Prototype _prototype = new ConcretePrototype("id1"); //浅拷贝会在拷贝的多个对象间的引用类型改变都会改变,因为引用的是一个地址 Prototype clone1 = _prototype.Clone() as ConcretePrototype; Console.WriteLine("Cloned1: " + clone1.Id); //深克隆和单独new一个对象的效果是一样的 Prototype clone2 = _prototype.SClone() as ConcretePrototype; Console.WriteLine("Cloned2: " + clone2.Id); Console.ReadLine(); } }
5、建造者模式(似乎有时也叫生成器模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)
典型应用类似ERP系统中的Bom表一样,一个产品对象由不同的物料对象组成。以下是示例
/// <summary> /// 产品类 /// </summary> public class Product { // 产品组件集合 private IList<string> parts = new List<string>(); // 把单个组件添加到产品组件集合中 public void Add(string part) { parts.Add(part); } public void Show() { Console.WriteLine("产品开始在组装......."); foreach (string part in parts) { Console.WriteLine("组件" + part + "已装好"); } Console.WriteLine("产品组装完成"); } } //建造者类 interface IBuilder { void BuildPartA(); void BuildPartB(); Product Product { get; } } //具体建造者实现类 public class Builder1 : IBuilder { Product product; public Builder1() { product = new Product(); } public void BuildPartA() { Product.Add("PartA"); } public void BuildPartB() { Product.Add("PartB"); } public Product GetProduct() { return product; } } //指挥调度者类 class Manufacturer { public void Construct(IBuilder builder) { builder.BuildPartA(); builder.BuildPartB(); } } // 客户端调用 class Client { static void Main(string[] args) { // 实例化指挥者 Manufacturer newManufacturer = new Manufacturer(); // 准备建造者 IBuilder productBuilder = null; // 实例调用具体建造者执行任务 productBuilder = new Builder1(); newManufacturer.Construct(productBuilder); productBuilder.Product.show(); //....可以实现其他具体建造者... } }