什么是单件模式? 就是构造函数为私有方法private,无法从外部创建对象,只能通过此类提供的一个静态方法获取对象。
什么情况下才应该使用单件模式呢?我直接使用静态方法不行吗,不是也不用创建对象吗?
于是,翻了下代码,找到了下面一个类,这个类使用单件模式的意义是什么?这是一个用于生成随机码的工具类,直接使用静态方法不行吗?
public class CheckCodeUtils
{
private static readonly Lazy lazy = new Lazy(() => new CheckCodeUtils());
public static CheckCodeUtils Instance { get { return lazy.Value; } }
private Random Rand { get; set; }
private CheckCodeUtils()
{
this.Rand = new Random();
}
public string Create(int length = 12)
{
StringBuilder str = new StringBuilder();
for (int i = 0; i < length; i++)
{
str.Append(Rand.Next(0, 9));
}
return str.ToString();
}
}单件模式确保一个类只有一个实例,并提供一个全局访问点。

巧克力工厂的锅炉控制对象,存储了锅炉的实时状态,例如是否空载,是否煮沸等。锅炉对象需要根据当前的状态去做相应的动作。如果状态维护的不对,就会非常危险。
为什么要用单件模式,就很容易理解了,如果存在多个对象的话,锅炉状态就会混乱,因为每个实例中的状态无法保证全局一致。
所以就得到了第一个答案,什么情况下需要使用单价模式: 需要确保数据状态全局统一,避免错乱。
如果我们的程序是单线程操作,这个很容易实现,只需要简单的if判断条件即可。
但是如果出现在多线程场景下,就需要考虑会不会创建出多个对象。
目前有很多固定的实现方式,例如常见的双重检查锁、以及c#固有的Lazy懒加载方式。
其中Lazy的实现方式,在上面示例代码中已经给出(虽然那个场景可能不需要使用单件模式)。
(1)数据库访问 DaoService,使用单例模式,避免重复重建数据库服务实例带来的性能开销
public class DaoService
{
private class IntercepterEqulityComparer : IEqualityComparer
{
public bool Equals(StandardInterceptor x, StandardInterceptor y)
{
return string.Equals(x.GetType().FullName, y.GetType().FullName, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(StandardInterceptor obj)
{
return obj.GetType().FullName.GetHashCode();
}
}
private static IDaoHandler handler;
private static Dictionary dicDaoSvc;
private static object lockObj;
private string connName = string.Empty;
//
// 摘要:
// 公共拦截器
public static readonly ConcurrentBag CommonInterceptors;
static DaoService()
{
handler = new DaoHandler();
dicDaoSvc = new Dictionary();
lockObj = new object();
CommonInterceptors = new ConcurrentBag();
CommonInterceptors.Add(new FlowControlInterceptor());
CommonInterceptors.Add(new DaoExceptionInterceptor());
}
private DaoService(string connName)
{
this.connName = connName;
}
//
// 摘要:
// 获取服务实例
//
// 参数:
// connName:
public static DaoService GetInstance(string connName)
{
DaoService value = null;
if (!dicDaoSvc.TryGetValue(connName, out value))
{
lock (lockObj)
{
if (!dicDaoSvc.TryGetValue(connName, out value))
{
value = new DaoService(connName);
dicDaoSvc[connName] = value;
}
}
}
return value;
}(2) KafkaProducer的单例实现, 避免重复kafka连接带来的开销。
public class KafkaProducer where T : ILog
{
private static readonly object LOCK_OBJ = new object();
private static IKafkaProducer Producer = null;
public static IKafkaProducer Instance
{
get
{
if (Producer == null)
{
lock (LOCK_OBJ)
{
if (Producer == null)
{
Producer = KafkaProducerProvider.Current.GetDefaultProducer(KafkaMessageSerializer.ProtobufDeserializer);
}
}
}
return Producer;
}
}
}1、需要全局访问,且需要确保全局状态统一,可以使用单件模式(例如全局缓存)
2、TPS较高的场合,如果初始化实例,需要高耗时或者占用资源较多时,可以通过单件模式避免重复创建实例带来的性能问题(例如数据库连接、配置加载)
3、学习了常用的几种单件模式的实现方式(静态方法、双重检查锁、Lazy懒加载方式)