zoukankan      html  css  js  c++  java
  • 单例模式

    最近看了很多关于单例模式的写法介绍,很多都有自己的特点,讨论的切入点也不一样。更重要的一点是高手讲解单例模式的时候,几乎不讲解为什么这么写(也就是语法上的意义)。今天就总结一下,和大家讨论一下。

    第一中实现方法:

     1  class Singleton
     2  {
     3      private :
     4          Singleton()
     5          {
     6          }
     7      public :
     8          static Singleton * instance()
     9          {
    10              if ( 0 == m_pInstance )
    11              {
    12                  m_pInstance = new Singleton();
    13              }
    14              return m_pInstance;
    15          }
    16      private:
    17          static Singleton * m_pInstance;
    18  };
    19  Singleton* Singleton::m_pInstance = 0;
    20 
    21 void fun(Singleton * p, Singleton *& q)
    22 {
    23     if(p == q)
    24     {
    25         cout << "right" <<endl;
    26     }
    27     return;
    28 }
    29 
    30 int main()
    31 {
    32     Singleton *ps = Singleton::instance();
    33     Singleton *ps1 = Singleton::instance();
    34     Singleton *ps2;
    35     ps2 = ps;
    36 
    37     if (ps2 == ps1)
    38     {
    39         cout << "right" << endl;
    40     }
    41     
    42     fun(ps, ps);
    43 
    44 
    45     return 0;
    46 }

    分析一下第一种实现方法:

    首先从语法上来分析:单例模式要求只能有一个实例,因此将这个实例封装成类之后,定义该类类型的成员。该成员定义为static类型,只能定义为指针类型或引用类型。返回实例的接口instance也定义为static,保证该实例之分配一个,且定义为static才可用类名直接调用,构造函数定义为私有的,保证不能创建新的对象。此外,并未声明且不定义构造函数和赋值操作符,实验证明不定义采用默认的不会产生新的实例,因为成员是指针类型,默认的构造函数和复制操作符是浅拷贝不会产生新对象。

    优缺点分析:简单,易学。但是,该单例模式是线程不安全的。且该实例有可能被无意delete掉,之后再使用的实=实例就是新产生的了。那么该实例怎么delete呢?可以由用户负责delete掉,万一忘了呢?怎么破?

     1 class  Singleton
     2 {
     3     private:
     4         Singleton()
     5         {
     6         }
     7 
     8         class Garbo
     9         {
    10             public :
    11                 ~Garbo()
    12                 {
    13                     if (Singleton::m_pInstance)
    14                     {
    15                         delete m_pInstance;
    16                     }
    17                 }
    18         };
    19         static  Garbo garbo;
    20         friend class Garbo;
    21     public:
    22         static Singleton * instance()
    23         {
    24             if ( 0 == m_pInstance)
    25             {
    26                 m_pInstance = new Singleton();
    27             }
    28             return m_pInstance;
    29         }
    30     
    31     private:
    32         static Singleton * m_pInstance;
    33 };
    34 Singleton* Singleton::m_pInstance = 0;
    35 Singleton::Garbo Singleton::garbo;
    36 
    37 void fun(Singleton * p, Singleton *& q)
    38 {
    39     if(p == q)
    40     {
    41         cout << "right" <<endl;
    42     }
    43     return;
    44 }
    45 
    46 int main()
    47 {
    48     Singleton *ps = Singleton::instance();
    49     Singleton *ps1 = Singleton::instance();
    50     Singleton *ps2;
    51     ps2 = ps;
    52 
    53     if (ps2 == ps1)
    54     {
    55         cout << "right" << endl;
    56     }
    57     
    58     fun(ps, ps);
    59 
    60 
    61     return 0;
    62 }

    第二种带回收机制的单例模式的分析:

      在单例类内定义一个内部类,内部类值实现析构函数,用于析构外部类的成员所指向的内存。原因:在外部类定义了内部类的static对象,在程序结束后会调用该静态类的析构函数,所以就可以实现析构了。需要注意的:需在外部类申明内部类为友员。须在类外初始化内部类类型的静态成员。

    优缺点:有了无需用户参与的垃圾回收机制,但是依然是线程不安全的。(注:VC6.0 没有看到调用内部类的析构函数)

     1 class Singleton
     2 {
     3     public :
     4         static Singleton& Instance()
     5         {
     6             static Singleton instance;
     7             return instance;
     8         }
     9     private :
    10         Singleton()
    11         {
    12 
    13         }
    14         Singleton(const Singleton &);
    15         Singleton& operator=(const Singleton&);
    16 };

    第三种方法是《Effective C++》中的,将单例类定义为函数的static变量,每次返回的都是同一个实例。该方法实现简单,在有些环境下是线程安全的(具体我也不太清楚,sorry)。也不用担心垃圾回收。

    作为一个菜鸟,只能写到这了,等日后学了多线程,再回来完善。

    最后:获取实例的函数可以返回引用和指针两种情况,第三种方法我认为应该让返回引用,返回指针会破坏封装性,比如我们可以直接delete掉。前两种返回指针。

  • 相关阅读:
    ALV实时刷新功能的实现
    sap中批量导入Excel表格中的数据
    从se11新建的表维护中,给维护的数据做限制处理,例如,只允许输入vp开头的数据
    abap之ranges使用
    Abap中LOOP循环时使用AT FIRST. 传数过程中出现一串 ******** ------解决办法
    Django项目-创建第一个页面
    Python3创建django项目
    Python3安装Pyyaml
    Appium命令行环境搭建及参数使用
    c# ABP 中开启新的事务
  • 原文地址:https://www.cnblogs.com/OrdinaryMiracle/p/5001201.html
Copyright © 2011-2022 走看看