本系列将和大家分享面向对象23种设计模式中常用的几种设计模式,本章主要简单介绍下创建型设计模式。
本章是面向对象23种设计模式系列开篇,首先我们来看下什么是设计模式?
面向对象23种设计模式:
1、面向对象语言开发过程中,遇到的种种场景和问题,提出了解决方案和思路,沉淀下来就变成了设计模式。
2、解决具体问题的具体招数---套路---站在前辈的肩膀上。
3、没有什么设计模式是完美无缺的,一种设计模式就是解决一类问题,通常设计模式在解决一类问题的同时,还会带来别的问题,我们设计者要做的事儿,就是要扬长避短,充分发挥长处!
设计模式可以大概分为三大类:
1、创建型设计模式:关注对象的创建。
2、结构型设计模式:关注类与类之间的关系。
3、行为型设计模式:关注对象和行为的分离。
我们要做的就是学习核心套路,这里就不做过多的描述,如果有机会会通过具体例子再和大家分享。下面我们正式进入本章主题。
创建型设计模式:关注对象的创建。(5个)
1、单例模式(Singleton Pattern)
单例模式:
就是限制了对象的创建,重用了对象。保证进程中,某个类只有一个实例。
即使是单例,变量也不是线程安全的,单例不是为了保证线程安全。
单例的好处就是单例,就是全局唯一的一个实例。
应对一些特殊情况,比如数据库连接池(内置了资源) ,全局唯一号码生成器。
单例可以避免重复创建,但是也会常驻内存,除非是真的有必要,否则就不要使用单例。
1.1、单例模式经典写法(懒汉式)
using System;using System.Threading;namespace SingletonPattern
{ ///
/// 懒汉式单例模式(经典写法) /// 单例类:一个构造对象很耗时耗资源类型。 ///
public class Singleton
{ ///
/// 构造函数耗时耗资源 ///
private Singleton()
{ long lResult = 0; for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(2000);
Console.WriteLine("{0}被构造一次", this.GetType().Name);
} ///
/// 全局唯一静态 重用这个变量 /// volatile 促进线程安全 让线程按顺序操作 ///
private static volatile Singleton _singleton = null; ///
/// 引用类型对象 ///
private static readonly object lockSingleton = new object(); ///
/// 公开的静态方法提供对象实例 ///
///
///
public static Singleton CreateInstance()
{ if (_singleton == null) //_singleton已经被初始化之后,就不要进入锁等待了 { //保证任意时刻只有一个线程进入lock范围 //也限制了并发,尤其是_singleton已经被初始化之后,故使用了双if来解决并发限制问题
lock (lockSingleton)
{ //Thread.Sleep(1000); //Console.WriteLine("等待锁1s之后才继续。。。");
if (_singleton == null) //保证只实例化一次 {
_singleton = new Singleton();
}
}
} return _singleton;
} public int iTotal = 0; ///
/// 既然是单例,大家用的是同一个对象,用的是同一个方法,那还会并发吗 还有线程安全问题吗? /// 即使是单例,变量也不是线程安全的,单例不是为了保证线程安全。 ///
public void Increment()
{ //lock (lockSingleton) //{
this.iTotal++; //} } public static void Show()
{
Console.WriteLine(_singleton.iTotal);
}
}
}
使用如下:
using System;using System.Collections.Generic;using System.Threading.Tasks;namespace SingletonPattern
{ ///
/// 为什么要有单例设计模式? /// 构造对象耗时耗资源,很多地方都需要去new, 这个方法 其他方法 其他类 ///
class Program
{ static void Main(string[] args)
{ try
{
{ //保证进程中,某个类只有一个实例 //1 构造函数私有化 避免别人还去new //2 公开的静态方法提供对象实例 //3 初始化一个静态字段用于返回 保证全局都是这一个
Singleton singleton1 = Singleton.CreateInstance();
Singleton singleton2 = Singleton.CreateInstance();
Singleton singleton3 = Singleton.CreateInstance();
Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
Console.WriteLine(object.ReferenceEquals(singleton3, singleton2));
}
{
Listtasks = new List(); for (int i = 0; i < 10000; i++)
{
tasks.Add(Task.Run(() =>
{
Singleton singleton = Singleton.CreateInstance();
singleton.Increment();
}));
}
Task.WaitAll(tasks.ToArray());
Singleton.Show(); //即使是单例,变量也不是线程安全的,单例不是为了保证线程安全。 //iTotal 是0 1 10000 还是其他的 //结果为:其他值,1到10000范围内都可能 线程不安全 }
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
1.2、饿汉式写法(静态构造函数)
using System;using System.Threading;namespace SingletonPattern
{ ///
/// 饿汉式 ///
public class SingletonSecond
{ private static SingletonSecond _singletonSecond = null; ///
/// 构造函数耗时耗资源 ///
private SingletonSecond()
{ long lResult = 0; for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(1000);
Console.WriteLine("{0}被构造一次", this.GetType().Name);
} ///
/// 静态构造函数:由CLR保证,程序第一次使用这个类型前被调用,且只调用一次。 ///
static SingletonSecond()
{
_singletonSecond = new SingletonSecond();
Console.WriteLine("SingletonSecond 被启动");
} ///
/// 饿汉式 只要使用类就会被构造 ///
///
///
public static SingletonSecond CreateInstance()
{ return _singletonSecond;
}
}
}
1.3、饿汉式写法(静态字段)
using System;using System.Threading;namespace SingletonPattern
{ ///
/// 饿汉式 ///
public class SingletonThird
{ ///
/// 静态字段:在第一次使用这个类之前,由CLR保证,初始化且只初始化一次。 /// 这个比构造函数还早 ///
private static SingletonThird _singletonThird = new SingletonThird(); //打印个日志
///
/// 构造函数耗时耗资源 ///
private SingletonThird()
{ long lResult = 0; for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(1000);
Console.WriteLine("{0}被构造一次", this.GetType().Name);
} ///
/// 饿汉式 只要使用类就会被构造 ///
///
///
public static SingletonThird CreateInstance()
{ return _singletonThird;
} public void Show()
{
Console.WriteLine("这里是{0}.Show", this.GetType().Name);
}
}
}
2、原型模式(Prototype Pattern)
原型模式:
换个方式创建对象,不走构造函数,而是内存拷贝。
单例的基础上升级了一下,把对象从内存层面复制了一下,然后返回。
是个新对象,但是又不是new出来的。
using System;using System.Threading;namespace PrototypePattern
{ ///
/// 原型模式:单例的基础上升级了一下,把对象从内存层面复制了一下,然后返回。 /// 是个新对象,但是又不是new出来的。 ///
public class Prototype
{ ///
/// 构造函数耗时耗资源 ///
private Prototype()
{ long lResult = 0; for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(2000);
Console.WriteLine("{0}被构造一次", this.GetType().Name);
} ///
/// 全局唯一静态 重用这个变量 ///
private static volatile Prototype _prototype = new Prototype(); ///
/// 公开的静态方法提供对象实例 ///
///
///
public static Prototype CreateInstance()
{
Prototype prototype = (Prototype)_prototype.MemberwiseClone(); //从内存层面复制
return prototype;
}
}
}
下面为了演示鼎鼎大名的三大工厂我们创建几个接口和类:
/// /// 种族/// public interface IRace
{ void ShowKing();
}/// /// 军队/// public interface IArmy
{ void ShowArmy();
}/// /// 英雄/// public interface IHero
{ void ShowHero();
}/// /// 资源/// public interface IResource
{ void ShowResource();
}/// /// 幸运值/// public interface ILuck
{ void ShowLuck();
}
using System;using FactoryPattern.War3.Interface;namespace FactoryPattern.War3.Service
{ ///
/// 人族(War3种族之一) ///
public class Human : IRace
{ public Human(int id, DateTime dateTime, string reamrk)
{ } public Human()
{ } public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Sky");
}
} public class HumanArmy : IArmy
{ public void ShowArmy()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "footman,火枪,骑士,狮鹫");
}
} public class HumanHero : IHero
{ public void ShowHero()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "大法师、山丘、圣骑士、血法师");
}
} public class HumanResource : IResource
{ public void ShowResource()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
}
}
}
using System;using FactoryPattern.War3.Interface;namespace FactoryPattern.War3.Service
{ ///
/// 不死族(War3种族之一) ///
public class Undead : IRace
{ public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "GoStop");
}
} public class UndeadArmy : IArmy
{ public void ShowArmy()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "食尸鬼,蜘蛛,雕像,战车,憎恶,冰霜巨龙");
}
} public class UndeadHero : IHero
{ public void ShowHero()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "DK、Lich、小强、恐惧魔王");
}
} public class UndeadResource : IResource
{ public void ShowResource()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
}
}
}
using System;using FactoryPattern.War3.Interface;namespace FactoryPattern.War3.Service
{ ///
/// War3种族之一 ///
public class ORC : IRace
{ public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Grubby");
}
} public class ORCArmy : IArmy
{ public void ShowArmy()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "大G、风骑士、蝙蝠、战车、牛头人");
}
} public class ORCHero : IHero
{ public void ShowHero()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "剑圣、小萨满、先知、牛头人酋长");
}
} public class ORCResource : IResource
{ public void ShowResource()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
}
}
}
using System;using FactoryPattern.War3.Interface;namespace FactoryPattern.War3.Service
{ ///
/// War3种族之一 ///
public class NE : IRace
{ public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
}
}
}
3、简单工厂(Simple Factory)
简单工厂:不直接new,把对象创建转移到工厂类。(简单工厂不属于23种设计模式)
核心代码如下:
using System;using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace SimpleFactory
{ ///
/// 简单工厂 ///
public class ObjectFactory
{ ///
/// 细节没有消失 只是转移 /// 转移了矛盾,并没有消除矛盾 /// 此处集中了矛盾 ///
///
///
///
///
public static IRace CreateRace(RaceType raceType)
{
IRace iRace; switch (raceType)
{ case RaceType.Human:
iRace = new Human(); break; case RaceType.Undead:
iRace = new Undead(); break; case RaceType.ORC:
iRace = new ORC(); break; case RaceType.NE:
iRace = new NE(); break; //每增加一个分支就需要修改代码
default: throw new Exception("wrong raceType");
} return iRace;
}
} ///
/// 种族类型枚举 ///
public enum RaceType
{
Human,
Undead,
ORC,
NE
}
}
using System;using FactoryPattern.War3.Interface;namespace SimpleFactory
{ ///
/// 玩家 ///
public class Player
{ public int Id { get; set; } public string Name { get; set; } ///
/// 面向抽象 ///
///
/// 种族 ///
public void PlayWar3(IRace race)
{
Console.WriteLine("******************************");
Console.WriteLine("This is {0} Play War3.{1}", this.Name, race.GetType().Name);
race.ShowKing();
}
}
}
using System;using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace SimpleFactory
{ ///
/// 简单工厂:非常简单的工厂 /// 工厂就是创建对象的地方 ///
class Program
{ static void Main(string[] args)
{ try
{
Player player = new Player()
{
Id = 123,
Name = "候鸟"
};
{
Human human = new Human();//1 到处都是细节 player.PlayWar3(human);
}
{
IRace human = new Human();//2 左边是抽象 右边是细节 player.PlayWar3(human);
}
{
IRace human = ObjectFactory.CreateRace(RaceType.Human); //3 没有细节 细节被转移 player.PlayWar3(human);
}
{
IRace undead = ObjectFactory.CreateRace(RaceType.Undead); //4 没有细节 细节被转移 player.PlayWar3(undead);
}
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
4、工厂方法模式(Factory Method Pattern)
工厂方法模式:
屏蔽对象的创建,留下了扩展空间。
把简单工厂拆分成多个工厂,保证每个工厂的相对稳定。
多new一次工厂,难免,中间层,屏蔽业务类变化的影响,而且可以留下创建对象的扩展空间。
using FactoryPattern.War3.Interface;namespace FactoryMethod.Factory
{ public interface IFactory
{ ///
/// 创建种族 ///
///
/// IRace CreateRace();
}
}
using System;using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace FactoryMethod.Factory
{ public class HumanFactory : IFactory
{ public virtual IRace CreateRace()
{ return new Human();
}
} ///
/// 后期可以对其扩展 ///
public class HumanFactoryAdvanced : HumanFactory
{ public override IRace CreateRace()
{
Console.WriteLine("123"); return new Human();
}
}
}
using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace FactoryMethod.Factory
{ public class UndeadFactory : IFactory
{ public IRace CreateRace()
{ return new Undead();
}
}
}
using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace FactoryMethod.Factory
{ public class ORCFactory : IFactory
{ public IRace CreateRace()
{ return new ORC();
}
}
}
using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace FactoryMethod.Factory
{ public class NEFactory : IFactory
{ public IRace CreateRace()
{ return new NE();
}
}
}
using System;using FactoryMethod.Factory;using FactoryPattern.War3.Interface;namespace FactoryMethod
{ ///
/// 工厂方法:把简单工厂拆分成多个工厂,保证每个工厂的相对稳定。 /// 但是要多new一次工厂? 难免,中间层,屏蔽业务类变化的影响,而且可以留下创建对象的扩展空间。 /// 开闭原则:对扩展开发,对修改封闭。 /// 工厂方法完美遵循了开闭原则 ///
class Program
{ static void Main(string[] args)
{ try
{
{ //human
IFactory factory = new HumanFactory();//包一层
IRace race = factory.CreateRace(); //何苦 搞了这么多工厂 还不是创建个对象 //以前依赖的是Human 现在换成了HumanFactory //1 工厂可以增加一些创建逻辑 屏蔽对象实例化的复杂度 //2 对象创建的过程中 可能扩展(尤其是ioc) }
{ //Undead
IFactory factory = new UndeadFactory();
IRace race = factory.CreateRace();
}
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
可以看出工厂方法模式,就是把简单工厂拆分成多个工厂,保证每个工厂的相对稳定。多new一次工厂,难免,中间层,屏蔽业务类变化的影响,而且可以留下创建对象的扩展空间。
另外工厂方法完美遵循了开闭原则,例如:Demo中原先我们有4个种族,分别为Human、Undead、ORC和NE,此时如果业务发生变化需要增加一个Five种族,
这时候我们只需要添加一个Five工厂类就好了,不会影响原来的代码。
using System;using FactoryPattern.War3.Interface;namespace FactoryPattern.War3.ServiceExtend
{ ///
/// War3种族之一 ///
public class Five : IRace
{ public Five()
: this(1, "old", 1) //当前类的构造函数 {
} public Five(int id, string name, int version)
{
} public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
}
}
}
using FactoryPattern.War3.Interface;using FactoryPattern.War3.ServiceExtend;namespace FactoryMethod.Factory
{ ///
/// 比如构造很复杂。。比如依赖其他对象 /// 屏蔽变化 ///
public class FiveFactory : IFactory
{ public virtual IRace CreateRace()
{ //return new Five();
return new Five(2, "New", 2);
}
}
}
5、抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式:
屏蔽对象的创建,约束强制保障产品簇。
创建一组密不可分的对象。
创建产品簇:创建一组密不可分的对象。
工厂+约束
倾斜的可扩展性设计,扩展种族很方便,增加产品很麻烦。
核心代码如下:
using FactoryPattern.War3.Interface;namespace AbstractFactory.Factory
{ ///
/// 一个工厂负责一些产品的创建 /// 产品簇 /// 单一职责就是创建完整的产品簇 ///
/// 继承抽象类后,必须显式的override父类的抽象方法。 ///
public abstract class FactoryAbstract
{ public abstract IRace CreateRace(); public abstract IArmy CreateArmy(); public abstract IHero CreateHero(); public abstract IResource CreateResource(); //倾斜的可扩展性设计:扩展种族很方便,增加产品(元素)很麻烦。 //public abstract ILuck CreateLuck(); //增加产品(元素)则每个种族的代码都要修改 }
}
using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace AbstractFactory.Factory
{ ///
/// 一个工厂负责一些产品的创建 ///
public class HumanFactory : FactoryAbstract
{ public override IRace CreateRace()
{ return new Human();
} public override IArmy CreateArmy()
{ return new HumanArmy();
} public override IHero CreateHero()
{ return new HumanHero();
} public override IResource CreateResource()
{ return new HumanResource();
}
}
}
using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace AbstractFactory.Factory
{ ///
/// 一个工厂负责一些产品的创建 ///
public class UndeadFactory : FactoryAbstract
{ public override IRace CreateRace()
{ return new Undead();
} public override IArmy CreateArmy()
{ return new UndeadArmy();
} public override IHero CreateHero()
{ return new UndeadHero();
} public override IResource CreateResource()
{ return new UndeadResource();
}
}
}
using System;using AbstractFactory.Factory;using FactoryPattern.War3.Interface;using FactoryPattern.War3.Service;namespace AbstractFactory
{ ///
/// 抽象工厂:创建一组密不可分的对象。 /// 创建产品簇:多个对象是个整体,不可分割。 ///
/// 工厂+约束 ///
/// 倾斜的可扩展性设计:扩展种族很方便,增加产品(元素)很麻烦。 ///
class Program
{ static void Main(string[] args)
{ try
{
Console.WriteLine("想要玩一款游戏,必须4大元素备齐"); //System.Data.SqlClient.SqlClientFactory //使用的就是抽象工厂模式 {
IRace race = new Undead();
IArmy army = new UndeadArmy();
IHero hero = new UndeadHero();
IResource resource = new UndeadResource(); //1 对象转移,屏蔽细节,让使用者更轻松 //2 对象簇的工厂 }
{
FactoryAbstract undeadFactory = new UndeadFactory();
IRace race = undeadFactory.CreateRace();// new Undead();
IArmy army = undeadFactory.CreateArmy();//new UndeadArmy();
IHero hero = undeadFactory.CreateHero();//new UndeadHero();
IResource resource = undeadFactory.CreateResource();//new UndeadResource(); }
{
FactoryAbstract humanFactory = new HumanFactory();
IRace race = humanFactory.CreateRace();
IArmy army = humanFactory.CreateArmy();
IHero hero = humanFactory.CreateHero();
IResource resource = humanFactory.CreateResource();
}
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
可以看出抽象工厂模式,屏蔽对象的创建,约束强制保障产品簇,创建一组密不可分的对象(例如:Demo中每个种族都有四个密不可分的元素,分别为Race、Army、Hero和Resource)。
另外抽象工厂模式是倾斜的可扩展性设计,扩展种族很方便,增加产品(元素)很麻烦,例如在Demo中如果产品簇增加一个Luck元素则每个种族的代码都需要修改。