单例模式(Singleton)
- 一、单例模式定义
- 二、单例模式说明
- 三、反对过多使用单例
- 四、少用单例模式时如何方便地引用到单一对象
- 1、让类具有计数功能来限制对象数量
- 2、设置成为类的引用,让对象可以被取用
- 3、使用类的静态方法
- 四、总结
一、单例模式定义
单例模式(Singleton)在GoF中的定义是:确认类只有一个对象,并且提供一个全局的方法来获取这个对象。
单例模式在实现时,需要程序设计语言的支持。只要具有静态类属性、静态类方法和重新定义类建造者存取层级。
二、单例模式说明
Singleton参与的在项目中参与角色说明如下:
- 能产生唯一对象类,并且提供“全局方法”让外界可以方便获取唯一的对象。
- 通常会把唯一的类对象设置为“静态类属性”。
- 习惯上会使用Instance作为全局静态方法的名称,通过这个静态函数可能获取“静态类属性”。
实现示例:
public class Singleton
{
private static Singleton _instance;
public static Singleton Instance
{
get{
if(_instance==null)
{
_instance=new Singleton();
}
return _instance;
}
}
private Singleton(){}
}
在类内定义一个Singleton类的“静态变量”_instance,并定义一个“静态属性”
。这里也应用了C#的getter存取运算符功能来实现Instance方法。
三、反对过多使用单例
单例好用的原因之一是:可以马上获取类对象,不必为了“安排对象传递”或“设置引用”而伤脑筋,想使用类对象时,调用类的Instance方法就可以马上获取对象,非常方便,但如果一直用下去,容易得“单例癖(Singletonitis)”,即过于沉迷于使用单例模式。
如果不使用单例模式或全局变量,最简单的对象引用方式就是:将对象当成“方法参数”,一路传到最后需要使用该对象的方法中,非常不方便且容易失控。
其实,产生这样矛盾的原因是:开发时过度使用“全局变量”及不仔细思考对象的“适当可视性”所造成的产物,并且多数还是在设计上出现问题导致的,这些是是可以避免的。
如果更深入探讨,单例模式还违反了“开—闭原则(OCP)”。因为通过Instance方式获取对象是“实现类”而不是“接口类”,该方式返回的对象包含了实现细节的实体类。
因此,当设计变更或需求增加时,程序设计师无法将其替代为其他类,只能更改原有的实现类内的程序代码,无法满足“对修改关闭”的要求。
与其这样还不如花点时间修改原有的设计。
四、少用单例模式时如何方便地引用到单一对象
1、让类具有计数功能来限制对象数量
在数量限制的类中加上“计数器”(静态成员属性)。每当类的建造者被调用时,就让计数器增加1,然后判断有没有超过限制的数量,如果超过,标记为无法使用,后续的对象功能也不可以被执行。
public class ClassWithCounter
{
protected static int m_ObjCounter=0;
protected bool m_bEnable=false;
public ClassWithCounter(){
m_ObjCounter++;
m_bEnable=m_ObjCounter==1? true:false;
if(!m_bEnable){
//当前数量已超1个
}
}
public void Operator(){
if(!m_bEnable)
return;
}
}
2、设置成为类的引用,让对象可以被取用
某个类的功能被大量使用时,可以将这个类对象设置为其他类中的成员,方便直接引用这些类。
这种实现方法是“依赖性注入”的方式之一,可以让被引用的对象不必通过参数传递的方式,就能被类的其他方法引用。
按照设置方式又可分为:
- 分别设置:目标类设置为其他类中的对象引用;
- 指定静态类:目标类设置为其他类的静态引用成员
3、使用类的静态方法
类的每一个静态方法都负责返回一个“资源生成工厂接口”。
四、总结
单例模式
- 优点:
- 可以限制对象的产生数量;
- 提供方便获取唯一对象的方法;
- 缺点:
- 容易造成设计思考不周和过度使用问题,但并不是要求设计者完全不使用这个模式,而是在仔细设计和特定的前提下,适当采用。
适用场景
- 网络在线游戏客户端,通过单例模式限制连接数,预防过多连接;
- 日志工具,受项目影响比较小,可设计为跨项目共享使用。