本文主要作为一个基础的普及文章,简单介绍单例模式的三种理解,为了在看单例模式攻防这篇文章做一些简单的铺垫。
单例模式是最简单的设计模式之一,提供了一种创建唯一对象的方式,用于保证仅有单个唯一的对象访问方式,可以直接访问而不需要或避免对该类的实例化。
应用于某些需要保证唯一对象的场景,比如配置信息类、连接池类、ID生成器类、全局变量类等,接下来介绍下三种常见的单例模式写法:
饿汉式
默认直接实例化的情况比较简单直接,缺点在于类一启动就申请了内存空间,即使没有被调用,因此有了第二种懒汉式写法,即在实际使用的时候才进行实例化来申请内存。
class Demo1
{//author: suoxd123@126.com
private Demo1() { }
private static Demo1 demoItem = new Demo1();
public Demo1 getInstance()
{
return demoItem;
}
}
懒汉式
懒汉式的单例保证了线程安全,也可以进行慢加载,只有在用到的时候才进行初始化和申请内存,调用效率比较高。
class Demo2
{//author: suoxd123@126.com
private static object objLock = new object();
private Demo2() { }
private volatile static Demo2 demoItem;
public static Demo2 getInstance()
{
if (demoItem == null)
{
lock (objLock)
{
if (demoItem == null)
{
demoItem = new Demo2();
}
}
}
return demoItem;
}
}
静态内部类式
这种写法通过在类中定义一个静态的内部类,在静态类中定义静态变量来进行访问,既保证了线程安全,也满足了慢加载。
class Demo3
{//author: suoxd123@126.com
private Demo3() { }
private static class InnerHelper
{
public static Demo3 demoItem = new Demo3();
}
public Demo3 getInstance()
{
return InnerHelper.demoItem;
}
}
常规理解的单例模式通常是指进程单例,即进程内实例唯一,也有一些环境需要用到线程单例,甚至集群单例,可以根据实际需要增加相关配置即可。
尽管可以通过单例模式进行唯一对象的生成,但单例模式也不是万能的,常被诟病为反模式的,还有一些其它问题比如
- 对面向对象的特性支持不友好
- 隐藏类之间的依赖
- 对代码扩展性不友好
- 可测试性不好
尽管通过private可以阻挡常规的调用的多次实例化,但是在一些极端的情况下,可能会有一定的问题,具体过程请点击查看:单例模式攻防进阶(https://www.zhenxiangsimple.com/2019/12/24/tech/design-single/)。