设计模式(0)简单工厂模式
源码地址
0 单例模式简介 0.0 单例模式定义单例模式是GOF二十三中经典设计模式的简单常用的一种设计模式,单例模式的基本结构需满足以下要求。
要满足上面的两点要求,应该很容易的想到:
1.该类的构造函数应该是私有的,不能随意被实例化是保证只有一个实例的前提。
2.该类需提供一个公开的且返回值类型为单例类类型的公用方法。
来看一下单例模式的基本结构图:
0.1 单例模式应用场景通过上面对单例模式基本定义的了解,单例模式的应用场景也就很明确了。
单例模式适用于各种系统中某个类的对象只能存在一个类似场景, 我们现在回顾一下上一篇简单工厂模式中的大致实现
简单工厂类 Factory { 创建英雄的静态方法 IHero CreateHero(string heroName) { switch (heroName) { : return new DH(); : return new WD(); : return new KOG(); : return new POM(); default: return null; } } }
恶魔猎手 DH : IHero { 秀出自己的技能 ShowSkills() { Console.WriteLine(); } }
通过简单工厂模式确实达到了接口隔离的目的,外部使用无需关注内部类的具体实现工程,只通过简单工厂类创建想要的对象即可,但这里有一个致命的问题就是,我们玩儿游戏的过程中,英雄会存在一个死亡和复活的场景,我们简单的把英雄祭坛理解为创建英雄的简单工厂,假设当我们复活英雄的时候,是通过工厂类创建英雄的一个过程,那么我们面临的问题就出现了,我本来一个6级的大恶魔猎手,由于走位过度风骚,走进了祭坛,现在在通过工厂创建的时候,由于是又重新new了一个对象,从祭坛中走出了一个萌叉叉的1级小恶魔猎手……
为保证我的那个6级大恶魔还是那个6级大恶魔,一身装备一个不少的走出祭坛,至此也就到了必须引入单例模式的时候了。
1 单例模式详解 1.0单例模式的基本实现-懒汉式单例模式按照单例模式的2个基本特征:私有的构造函数和公开的GetInstance方法。将DH类进行如下改造,代码的具体意图已经通过注释详细解释。
恶魔猎手 DH : IHero { DH dh; 私有的构造函数,能够保证该类不会在外部被随意实例化,是保证该类只用一个实例的基本前提 DH() { } 定义一个静态的公开的GetInstance方法供外部得到DH类唯一实例是调用 DH GetInstance() { //先判断dh是否已经被实例化,若未被实例化,先实例化得到DH类的实例 (dh == null) { dh = new DH(); } return dh; } 秀出自己的技能 ShowSkills() { Console.WriteLine(); } }
修改Factory简单工厂类中创建DH实例部分的代码
简单工厂类 Factory { 创建英雄的静态方法 IHero CreateHero(string heroName) { switch (heroName) { : : return new WD(); : return new KOG(); : return new POM(); default: return null; } } }
客户端测试
static void Main(string[] args) { IHero dh1 = Factory.CreateHero(); IHero dh2 = Factory.CreateHero(); if (dh1.Equals(dh2)) Console.WriteLine(); else Console.WriteLine(); IHero wd1 = Factory.CreateHero(); IHero wd2 = Factory.CreateHero(); if (wd1.Equals(wd1)) Console.WriteLine(); else Console.WriteLine(); Console.ReadLine(); }
输出结果如下
至此我们对DH这个类应用了单例模式来确保无论何时走出祭坛的都是同一个DH对象,从DH对象被实例化的实际来看,是在被使用的时候才会被创建,这种方式被成为懒汉式单例模式
有一天突发奇想,我建造两个英雄祭坛(两个简单工厂类),用我APM500+的超快手速,同时在两个祭坛里生产同一个英雄,发现我拥有了2个6级大恶魔……(当然了,实际中不会有这个bug存在)
这就是基本懒汉式单例模式要面对的多线程问题,也就是说基本懒汉式单例模式的写法是无法做到线程级别安全的。
问题的关键就在获取DH类实例的GetInstance方法的内部实现中
if (dh == null) { dh = new DH(); } return dh;