您的位置:首页 > 其它

[设计模式]SINGLETON(单件)_对象创建型模式

2017-07-31 08:59 501 查看

1. 意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。


2. 动机

对一些类来说,只有一个实例是很重要的。虽然系统中可以有许多打印机,但却只应该有一个打印假脱机( printer spooler),只应该有一个文件系统和一个窗口管理器。一个数字滤波器只能有一个 A / D转换器。一个会计系统只能专用于一个公司。
我们怎么样才能保证一个类只有一个实例并且这个实例易于被访问呢?一个全局变量使得一个对象可以被访问,inng kk。
一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。这就是Singleton模式。


3. 适用性

在下面的情况下可以使用 S i n g l e t o n模式


- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

- 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

4. 结构

5. 参与者

定义一个 I n s t a n c e操作,允许客户访问它的唯一实例。 I n s t a n c e是一个类操作(即S m a l l t a l k中的一个类方法和 C + +中的一个静态成员函数)。

可能负责创建它自己的唯一实例。

6. 协作

客户只能通过S i n g l e t o n的I n s t a n c e操作访问一个S i n g l e t o n的实例。

7. 效果及其优点

对唯一实例的受控访问

缩小名空间 S i n g l e t o n模式是对全局变量的一种改进。它避免了那些存储唯一实例的全局变量污染名空间。

允许对操作和表示的精化 可以用扩展类来实现一定功能,例如运行时刻配置应用

允许可变数目的实例 ,你可以改变

比类操作更灵活,另一种封装单件功能的方式是使用类操作(即 C + +中的静态成员函数或者是 S m a l l t a l k中的类方法)。但这两种语言技术都难以改变设计以允许一个类有多个实例。此外,C + +中的静态成员函数不是虚函数,因此子类不能多态的重定义它们。

8. 实现

1) 保证一个唯一的实例S i n g l e t o n模式使得这个唯一实例是类的一般实例,但该类被写成只有一个实例能被创建。做到这一点的一个常用方法是将创建这个实例的操作隐藏在一个类操作(即一个静态成员函数或者是一个类方法)后面,由它保证只有一个实例被创建。这个操作可以访问保存唯一实例的变量,而且它可以保证这个变量在返回值之前用这个唯一实例初始化。这种方法保证了单件在它的首次使用前被创建和使用。

在C + +中你可以用 S i n g l e t o n类的静态成员函数 I n s t a n c e来定义这个类操作。 S i n g l e t o n还定义了一个静态成员变量 _ i n s t a n c e,它包含了一个指向它的唯一实例的指针。

2) 创建S i n g l e t o n类的子类主要问题与其说是定义子类不如说是建立它的唯一实例,这样客户就可以使用它。事实上,指向单件实例的变量必须用子类的实例进行初始化。最简单的技术是在 S i n g l e t o n的I n s t a n c e操作中决定你想使用的是哪一个单件

下面是Muduo网络库实现的代码:

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef MUDUO_BASE_SINGLETON_H
#define MUDUO_BASE_SINGLETON_H

#include <boost/noncopyable.hpp>
#include <assert.h>
#include <stdlib.h> // atexit
#include <pthread.h>

namespace muduo
{

namespace detail
{
// This doesn't detect inherited member functions!
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions template<typename T>
struct has_no_destroy
{
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template <typename C> static char test(decltype(&C::no_destroy));
#else
template <typename C> static char test(typeof(&C::no_destroy));
#endif
template <typename C> static int32_t test(...);
const static bool value = sizeof(test<T>(0)) == 1;
};
}

template<typename T>
class Singleton : boost::noncopyable
{
public:
static T& instance()
{
//保证init_routine()函数在本进程执行序列中仅执行一次。
pthread_once(&ponce_, &Singleton::init);
assert(value_ != NULL);
return *value_;
}

private:
//默认构造函数
Singleton();
//默认析构函数
~Singleton();

static void init()
{
//初始化value_,并把其清零
value_ = new T();
if (!detail::has_no_destroy<T>::value)
{
//在进程退出时回收资源
::atexit(destroy);
}
}
//回收资源
static void destroy()
{
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
T_must_be_complete_type dummy; (void) dummy;

delete value_;
value_ = NULL;
}

private:
//pthread_once参数
static pthread_once_t ponce_;
//指向一个实例
static T*             value_;
};

//static需要在类外进行初始化
template<typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;

template<typename T>
T* Singleton<T>::value_ = NULL;

}
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: