天天看点

设计模式--单例模式

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

既然单例模式只允许存在一个对象,那么对象的拷贝,赋值就都是不允许的,因此把拷贝构造函数、赋值操作符全部声明为private

第一种实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<code>class</code> <code>Singleton</code>

<code>{</code>

<code> </code><code>private</code><code>:</code>

<code>     </code><code>static</code> <code>Singleton *m_instance;</code>

<code>     </code><code>Singleton(){}</code><code>//隐藏构造函数</code>

<code>     </code><code>Singleton(</code><code>const</code> <code>Singleton &amp;){}</code><code>//隐藏拷贝构造函数</code>

<code>     </code><code>Singleton&amp; operator=(</code><code>const</code> <code>Singleton &amp;a){}</code><code>//隐藏赋值操作符</code>

<code>     </code><code>~Singleton(){}</code><code>//隐藏析构函数</code>

<code> </code><code>public</code><code>:</code>

<code>    </code><code>static</code> <code>Singleton *getInstance()</code>

<code>    </code><code>{</code>

<code>        </code><code>if</code><code>(m_instance == NULL)</code>

<code>            </code><code>m_instance =</code><code>new</code> <code>Singleton;</code>

<code>        </code><code>return</code> <code>m_instance;</code>

<code>    </code><code>}</code>

<code>    </code> 

<code>};</code>

<code>Singleton * Singleton::m_instance = NULL;</code>

这种实现很明显满足单例模式的要求,但是有两个问题 (1)我们new的对象没有被delete,(2)这种设计不是线程安全的(两个线程可能同时判断m_instance == NULL,这样就有两个实例被创建了),为了解决上面的问题,第二种实现如下

第二种实现

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

<code>     </code><code>class</code> <code>DelInstance</code>

<code>     </code><code>{</code>

<code>     </code><code>public</code><code>:</code>

<code>        </code><code>~DelInstance()</code>

<code>        </code><code>{</code>

<code>            </code><code>if</code><code>(Singleton::m_instance)</code>

<code>                </code><code>delete</code> <code>Singleton::m_instance;</code>

<code>        </code><code>}</code>

<code>     </code><code>};</code>

<code>     </code><code>static</code> <code>DelInstance delIns;</code><code>//负责回收new出来的对象;</code>

<code>            </code><code>lock();</code><code>//加锁(lock 和 unlock是随便写的函数,c++本身没有)</code>

<code>            </code><code>if</code><code>(m_instance == NULL)</code>

<code>                </code><code>m_instance =</code><code>new</code> <code>Singleton;</code>

<code>            </code><code>unlock();</code><code>//释放锁</code>

<code>Singleton::DelInstance Singleton::delIns;</code>

这里我们使用了另一个私有内嵌类DelInstance,在Singleton内定义了一个静态的的对象delIns来负责回收new出来的对象,因为静态对象delIns在程序结束时会自动调用自己析构函数从而释放m_instance指向的内存,这里新手可能会犯两个错误:

1、不使用额外的类,直接把delete语句写在singleton的析构函数中。这种做法是错误的,因为我们是通过new出来的singleton实例,程序结束时不会自动调用析构函数,再者如果真的调用了就会进入一个无限循环的状态,即singleton的析构函数是为了删除一个singleton对象,删除该对象时,又会调用singleton的析构函数,这样一直循环下去。

2、delIns成员不定义成static。这也是错误的,如果delIns不是static,那么delIns就要等到singleton对象析构时才会析构,但是delIns的目的就是要析构singleton,这就矛盾了。如果delIns是static的,他的生命期和他所在的类对象没有关系,他相当于是全局的,当他的生命期到的时候就会自动析构,从而析构singleton。

getInstance中我们使用了double-check来保证线程安全,只有当m_instance是NULL时,线程才会加锁。这样也保证了只创建了一个对象实例。

第三种实现

<code>Singleton * Singleton::m_instance =</code><code>new</code> <code>Singleton;</code>

这是属于饿汉模式,即一开始就创建一个类的实例,以后都返回其地址,是线程安全的。

第四种实现

<code>     </code><code>static</code> <code>Singleton s;</code>

<code>        </code><code>return</code> <code>&amp;s;</code>

<code>Singleton Singleton::s;</code>

饿汉模式,这种实现定义一个私有的静态对象实例,(注意不能在类中定义自身的非静态对象,因为这样会形成无限循环定义,而静态对象因为保证只有一个副本,因此不会循环定义),这也是线程安全的

第五种实现

<code>        </code><code>lock();</code><code>//c++11 可以不用加锁</code>

<code>        </code><code>static</code> <code>Singleton s;</code>

<code>        </code><code>unlock();</code>

注意

本文转自tenos博客园博客,原文链接:http://www.cnblogs.com/TenosDoIt/p/3639395.html,如需转载请自行联系原作者

继续阅读