设计模式实例之创建型模式(Singleton、Abstract Factory、Builder)讲解
单件模式(Singleton)
所谓的单件模式,就是说在系统中,一个类只存在唯一的实例,同时提供一个唯一的访问方法。
在我们的开发中,经常会发生使用唯一对象的情况,例如Web开发中,要记录网站访问人数的对象;程序属性配置的对象;网络编程中,只能建立一个连接的对象等等,类似于这些应用场景,都可以应用单件模式来处理。
下面举个例子来说明单件模式的使用,例子的功能是程序的配置信息管理,需要提供一个对配置的添加及读取方法,同时,只允许创建一个配置管理类的实例,代码如下:
{
private Dictionary<string, string> lsConfig = new Dictionary<string, string>();
/// <summary>
/// 私有构造函数,防止外部程序调用创建新实例
/// </summary>
private SingletonConfig()
{
}
public void Add(string key, string value)
{
lsConfig.Add(key, value);
}
public string Get(string key)
{
if (lsConfig.ContainsKey(key))
{
return lsConfig[key];
}
else
{
return null;//也可抛出异常
}
}
private static SingletonConfig _instance;
/// <summary>
/// 配置类实例访问对象
/// </summary>
public static SingletonConfig Instance
{
get {
if (_instance == null)
{
_instance = new SingletonConfig();
}
return _instance;
}
}
}
上面的代码有两个需要注意的地方,一是构造函数申明为私有类型,这可以预防代码通过构造函数的方法来生成新的实例,如下面的代码将会引起编译器错误:
SingletonConfig s = new SingletonConfig();
第二是后面的全局静态变量“Instance”,这个地方保证了外部访问到的,是唯一的配置实例。在代码使用的时候,就可以保证在任何地方调用配置类的方法,都只有Instance这个入口,保证了数据的唯一性。如下面的调用方法,不论在哪调用,都可以保证配置信息能正确的加入。
{
SingletonConfig.Instance.Add("Base", "Base Value");
TestA();
TestB();
Console.WriteLine(SingletonConfig.Instance.Get("A"));
Console.WriteLine(SingletonConfig.Instance.Get("B"));
Console.ReadLine();
}
private static void TestA()
{
SingletonConfig.Instance.Add("A", "A Value");
}
private static void TestB()
{
SingletonConfig.Instance.Add("B", "B Value");
}
单件模式的另一种用处,是用于控制多个实例的情况,例如需要做一个数据库连接池管理的操作,可以控制数据库连接池的大小,根据请求动态的分配连接对象。此时,可以这样设计单件类,如下:
{
private int _id;
private DataConnectionPool(int id)
{
this._id = id;
}
public string DataProcess(string key)
{
Release(_id);
return "Process:"+key;
}
private static Dictionary<int, DataConnectionPool> lsInstance;
private static readonly int POOL_NUM = 5;
private static Queue<int> lsFree = new Queue<int>();//当前可用队列
//将使用完的进程放入队列待用
private static void Release(int i)
{
lsFree.Enqueue(i);
}
public static DataConnectionPool Instance
{
get
{
if (lsInstance == null)
{
//根据配置的连接池实例化对象
for (int i = 0; i < POOL_NUM; i++)
{
lsInstance.Add(i, new DataConnectionPool(i));
lsFree.Enqueue(i);
}
}
if (lsFree.Count > 0)
{
//取出可以使用的实例
return lsInstance[lsFree.Dequeue()];
}
else
{
return null;//或者抛出异常
}
}
}
}
上面程序只是简单的演示,实际应用可以根据情况进行演变,不知道这样说明,大家明白了么。设计模式书里面还有一个单件子类的说明,所谓的单件子类,是指单件返回的实体类型可能会有多个子类,因此,需要有一种方式来决定返回哪个子类的实例或者动态改变当前实例的方法,其实简单点说就是返回实现相同接口的不同实例的功能。打个简单比方来说,一家卖包子的店,虽然它卖的是包子,不过可能会卖菜包,也可能卖肉包,也有可能是糖包等等,不过不管卖什么包子,都只有一个买包子的入口,这样说不知道大家明白么?