创建型模式--单例

1、意图

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

2、结构

 

3、参与者

  Singleton:定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作(即C++中的一个静态成员函数)。负责创建它自己的唯一实例。

4、适用性

  在下面的情况下可以使用Singleton模式:

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

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

5、代码示例

// 迷宫工厂,对于Maze应用来说仅需一个实例,
// 对于所有迷宫部件的构建都是可用的,所以用单例模式实现
class MazeFactory
{
public:
    static MazeFactory* Instance();
protected:
    // 构造函数为保护属性,外部不能直接通过构造函数实例化对象
    MazeFactory();
privatestatic MazeFactory* _instance;
};

MazeFactory* MazeFactory::instance = 0;
MazeFactory* MazeFactory::Instance()
{
    if(_instance == 0)
    {
        _instance = new MazeFactory;
    }
    return _instance;
}
// 通过环境变量选择迷宫的种类,并根据环境变量的值增加代码用于实例化适当的MazeFactory子类
MazeFactory* MazeFactory::Instance()
{
    if (_instance == 0)
    {
        const char* mazestyle = getenv("MAZESTYLE");
        if (strcmp(mazestyle, "bombed") == 0)
        {
            _instance = new BombedMazeFactory;
        }
        else if (strcmp(mazestyle,"enchanted") == 0)
        {
            _instance = new EnchantedMazeFactory;
        }
        // ...other possible subclasses
        else
        {
            _instance = new MazeFactory;
        }
    }
    return _instance;    
}

以上代码仍存在线程安全性问题,多线程应用下,可能会导致创建出多个实例。这会,需要通过加锁处理

MazeFactory* MazeFactory::Instance()
{
    if(_instance == 0)
    {
        Lock(); // C++ 没有直接的上锁操作,这里仅表示上锁,真正调用的可能是posix锁或boost锁
        if(_instance == 0)
        {
            _instance = new MazeFactory;
        }
        UnLock(); // C++ 没有直接的解锁操作,这里仅表示解锁,真正调用的可能是posix锁或boost锁
    }
    return _instance;
}

以上介绍的实例创建都是在运行时第一次调用Instance()发生的时刻,这种方式称之为懒汉式单例,为避免存在线程安全的问题,需加锁进行同步处理。

还有一种单例方式,即饿汉式单例,通过全局静态初始化方式创建实例,不存在线程安全问题。静态初始化发生在程序开始后,进入主函数前,由主线程进行初始化,所以不存在线程安全问题。

MazeFactory* MazeFactory::instance = new MazeFactory;
MazeFactory* MazeFactory::Instance()
{
    return _instance;
}

6、总结

  单例模式保证全局该类只有一个实例对象,用以替代全局变量。

  单例类需将构造函数声明为私有或保护属性,以防止外部创建。并需提供一个instance()的接口返回该全局唯一的实例以给外部使用。

  单例模式有懒汉式单例和饿汉式单例两种,懒汉式单例在第一次调用instance()时创建实例,为需要时才创建,存在线程安全问题。饿汉式单例通过全局静态初始化创建实例,不管需不需要,都会创建,不存在线程安全问题。

  当需要在运行时刻知道某些信息才能创建实例时,采用懒汉式单例。

posted @ 2022-05-02 15:27  流翎  阅读(45)  评论(0)    收藏  举报