文章目录
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。
一道巧克力工厂锅炉的题
先看这个类:
开始的时候, 锅炉是空的, 所以也没有煮沸.
fill()方法(填充), 填充锅炉的时候, 锅炉必须是空的, 一旦填满了, 那么empty就改为false, 表示填满了. 刚填满肯定不是煮沸状态, 所以boiled也是false.
drain()方法(抽取), 只有锅炉是满的并且煮沸之后才能抽取巧克力液体, 抽取完了, 锅炉就又空了 empty改为true.
boil()方法(煮), 煮混合液体, 要求锅炉的前提状态必须是满的 empty为false, 并且还没煮沸 boiled为false. 一旦煮沸了, 就把boiled改成true.
这个工序很好, 但是必须保证只有一个锅炉, 那么该怎么做? 请写出代码.
实现
存在多线程环境下没法达到真正单例,ChocolateBoiler:
namespace SingletonPattern
{
public class ChocolateBoiler
{
public bool Empty { get; private set; }
public bool Boiled { get; private set; }
private static ChocolateBoiler _uniqueInstance;
private ChocolateBoiler()
{
Empty = true;
Boiled = false;
}
public static ChocolateBoiler GetInstance()
{
return _uniqueInstance ?? (_uniqueInstance = new ChocolateBoiler());
}
public void Fill()
{
if (Empty)
{
Empty = false;
Boiled = false;
}
}
public void Drain()
{
if (!Empty && Boiled)
{
Empty = true;
}
}
public void Boil()
{
if (!Empty && !Boiled)
{
Boiled = true;
}
}
}
}
使用[MethodImpl(MethodImplOptions.Synchronized)]
解决,SynchronizedChocolateBoiler:
using System.Runtime.CompilerServices;
namespace SingletonPattern
{
public class SynchronizedChocolateBoiler
{
public bool Empty { get; private set; }
public bool Boiled { get; private set; }
private static SynchronizedChocolateBoiler _uniqueInstance;
private SynchronizedChocolateBoiler()
{
Empty = true;
Boiled = false;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static SynchronizedChocolateBoiler GetInstance()
{
return _uniqueInstance ?? (_uniqueInstance = new SynchronizedChocolateBoiler());
}
public void Fill()
{
if (Empty)
{
Empty = false;
Boiled = false;
}
}
public void Drain()
{
if (!Empty && Boiled)
{
Empty = true;
}
}
public void Boil()
{
if (!Empty && !Boiled)
{
Boiled = true;
}
}
}
}
再加一层判断来减少锁的开销,DoubleCheckChocolateBoiler:
namespace SingletonPattern
{
public class DoubleCheckChocolateBoiler
{
public bool Empty { get; private set; }
public bool Boiled { get; private set; }
private static volatile DoubleCheckChocolateBoiler _uniqueInstance;
private static readonly object LockHelper = new object();
private DoubleCheckChocolateBoiler()
{
Empty = true;
Boiled = false;
}
public static DoubleCheckChocolateBoiler GetInstance()
{
if (_uniqueInstance == null)
{
lock (LockHelper)
{
if (_uniqueInstance == null)
{
_uniqueInstance = new DoubleCheckChocolateBoiler();
}
}
}
return _uniqueInstance;
}
public void Fill()
{
if (Empty)
{
Empty = false;
Boiled = false;
}
}
public void Drain()
{
if (!Empty && Boiled)
{
Empty = true;
}
}
public void Boil()
{
if (!Empty && !Boiled)
{
Boiled = true;
}
}
}
}
来源
本文含有隐藏内容,请 开通VIP 后查看