[设计模式]单例模式

xiaoxiao2021-02-28  59

简介


单例模式(Singleton Pattern)保证一个类只有一个实例,并提供一个访问它的全局访问点。

单例模式是一种对象创建型模式 (可参考 设计模式 创建型模式)。

单例模式是设计模式中最简单的模式。它的用途就是使得类的一个对象成为系统中的 唯一实例。

 

结构


图-单例模式结构图

Singleton : 定义一个接口 Instance () 使得客户端可以访问它的唯一实例。

动机


在以下情况中,可以考虑应用单例模式:

保证一个类只有一个实例,并提供一个访问它的全局访问点。 当唯一的实例应该对子类可扩展,并且用户应该可以在不改变代码的情况下使用扩展的实例。

实际应用场景

一些资源管理器常常设计成单例模式。

在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中。

每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。任务管理器中难以启动两个相同的task。

要点


1、一个类只能有一个实例。 需要定义一个该类的 静态私有变量,使这个类的所有对象都共用这个实例。 

2、实例必须由类自行创建。

单例模式的类只能提供 私有的构造函数。如此,才能保证外部无法实例化这个类的对象。

3、必须提供获取实例的方法。

单例模式的类必须提供一个公共的 静态函数用于创建或获取它本身的 静态私有对象。

实例


1、懒汉式

你不找懒汉,懒汉根本就懒得去初始化自己的实例。 

instance 初始时没有初始化,只有当第一次调 getInstance() 时才创建实例。

缺点:当有两个线程调 getInstance() 方法,当它们同时执行到 if (null == instance) 这行代码, instance 为 null。

继续向下执行,会生成两个实例,违背了单例模式的初衷。 

public  class LazySingleton {      private LazySingleton() {         System.out.println("Singleton()");     }      private  static LazySingleton instance =  null;           public  static LazySingleton getInstance() {          if ( null == instance) {             instance =  new LazySingleton();         }                  return instance;     } }

2、饿汉式

饿汉根本等不及别人来找他,不管三七二十一先初始化了自身的实例,生怕自己饿着了。

类默认先直接初始化一个实例,以后调用 getInstance() 总是返回这个已创建好的实例。

缺点:在没有必要获取实例时,已经预先产生了开销。

优点:规避了懒汉式方法的线程问题,不用显示编写线程安全代码。 public  class HungerSinleton {      private HungerSinleton() {         System.out.println("Singleton()");     }           private  static HungerSinleton instance =  new HungerSinleton();           public  static HungerSinleton getInstance() {          return instance;     } }

3、双重锁的形式

如果既不想在没有调用 getInstance() 方法时产生开销,又不想发生线程安全问题,就可以采用双重锁的形式。

public  class SyncSingleton {      private SyncSingleton() {         System.out.println("Singleton()");     }           private  static SyncSingleton instance =  null;           public  static SyncSingleton getInstance() {          if ( null == instance) {              synchronized(SyncSingleton. class) {                  if ( null == instance) {                     instance =  new SyncSingleton();                 }             }         }          return instance;     } }

注:在外面判断了instance实例是否存在,为什么在锁定后又要在内部又判断一次?

这是因为,如果 instance 为 null 时有两个线程同时调用 getInstance(),由于 synchronized 机制,只有一个线程可以进入,另一个需要等待。

这时如果没有第二道 instance 是否为 null 的判断,就可能发生第一个线程创建一个实例,而第二个线程又创建一个实例的情况。

C++版单例模式

下面是一个采用饿汉式的例子 #include  " stdafx.h " #include <iostream> using  namespace std; class Singleton { private:      static Singleton *m_instance;     Singleton()     {         cout <<  " Singleton Construct " << endl;     } public:      static Singleton* GetInstance()     {          return m_instance;     } }; Singleton* Singleton::m_instance =  new Singleton(); int main() {      // Singleton *pSingletonA = new Singleton;   // 编译会报错,因为不能访问私有函数     Singleton *pSingletonA = Singleton::GetInstance();     Singleton *pSingletonB = Singleton::GetInstance();      if (pSingletonA == pSingletonB)         cout <<  " Same Instance " << endl;      return  0; } View Code

推荐阅读


本文属于 设计模式系列。  

参考资料


《大话设计模式》

《HeadFirst设计模式》
转载请注明原文地址: https://www.6miu.com/read-66716.html

最新回复(0)