【设计模式(三)】单例模式——单例有几种写法?
有一回对我说道,“你写过编程么?”我略略点一点头.他说,“写过,……我便考你一考.单例模式,是怎样写的?”我想,讨饭一样的人,也配考我么?便回过脸去,不再理会.孔乙己等了许久,很恳切的说道,“不能写罢?……我教给你,记着!
单例模式(Singleton Pattern)
单例模式是 Java 中最简单的设计模式之一。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式三要素:1.单例类只能有一个实例。 2.单例类必须自己创建自己的唯一实例。 3.单例类必须给所有其他对象提供这一实例。
应用场景
1.游戏开发中的跟随主角视角的摄像头,一般只有一个
2.要求生产唯一序列号,用来防伪
3.WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来
4.创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等
单例模式的四种写法
虽然演示语言是typescript,最终以javascript实现,而js没有多线程,不用考虑线程安全问题。但笔者依然会列出其中的线程安全问题,ts不考虑,java、c还是要的。
懒汉模式
class SingleTest { private static instance: SingleTest; constructor() { } public static getInstance(): SingleTest { if(this.instance == null) this.instance = new SingleTest(); return this.instance; } }
这是最基本的实现方式,为什么叫懒汉?因为要等别人调用了你才实例化对象,有够懒的。缺点很明显:不支持多线程。如果要保证线程安全,需要加锁synchronized,当然也会影响效率。
饿汉模式
class Singleton { private static instance:Singleton = new Singleton(); constructor (){} public static getInstance(): Singleton { return this.instance; } }
很常用的模式。为什么叫饿汉?因为类在装载的时候你就实例化了,别人还没上桌你就吃完了,饿死鬼投胎!容易写,而且执行效率会提高。缺点也很明显:类加载时就初始化,浪费内存,容易产生垃圾对象。
以下模式为多线程语言的设计模式,所以不用ts演示了。
双检锁/双重校验锁(DCL,即 double-checked locking)
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
登记式/静态内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
枚举
public enum Singleton { INSTANCE; public void whateverMethod() { } }
实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。但是需要JDK1.5 之后加入的enum 特性才可使用。
孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说,“对呀对呀!……单例模式有四样写法,你知道么?