可继承扩展的单例实现

最近在代码阅读中看到了一种可继承的单例实现,对使用者而言通过单例基类到定义的静态接口获取实例,而不必关心实际的单例实现。灵活性上,可通过继承的重写虚接口的方式实现单例功能的扩展。基础代码如下:

/* TestSingleton.h */

#include <iostream>
using namespace std;

#define ClassName(klass) (#klass)

class SingletonBase;
namespace
{
    SingletonBase* ptr_single_instance = nullptr;
}

class SingletonBase
{
public:
    SingletonBase();
    ~SingletonBase();

    // 虚接口
    virtual void TestSingleton();

    static SingletonBase* Get();
};

SingletonBase::SingletonBase()
{
    ptr_single_instance = this;
}

SingletonBase::~SingletonBase()
{

}

SingletonBase* SingletonBase::Get()
{
    return ptr_single_instance;
}

void SingletonBase::TestSingleton()
{
    cout << ClassName(SingletonBase) << std::endl;
}

class SingletonImp1 : public SingletonBase
{
public:
    SingletonImp1();
    ~SingletonImp1();

    virtual void TestSingleton() override;
};

SingletonImp1::SingletonImp1()
    : SingletonBase()
{

}

SingletonImp1::~SingletonImp1()
{
}

void SingletonImp1::TestSingleton()
{
    cout << ClassName(SingletonImp1) << std::endl;
}

void GoTest()
{
    //使用者实际选择创建何种单例,而不是在Get接口中new
    SingletonImp1* ptr_single_imp = new SingletonImp1();
    SingletonBase::Get()->TestSingleton();
}

当然在扩展性增强的同时也带来问题:相对于传统单例实现方式–在Get接口中new一个当前类型的实例,此种单例实例的创建暴露给了使用者,需要由使用者事先选择并创建指定子类型的实例,然后其他地方获取单例对象使用。

单例使用心得

单例便于单例类型中的接口调用,避免了类型上功能相互调用时参数传递的麻烦。但单例使用也存在一定的问题:
1. 单例的生命周期不易控制;
2. 单例使得类型间的依赖更加隐蔽且难以管理;
3. 单例中的定义的功能接口不易继承扩展:例如在项目开发中错误信息提示窗口统一在窗口右上角提示。实现上可通过定义消息提示的单例对象,在程序出错处调用单例对象的接口完成消息提示。随着功能的演进,又有了新的需求:消息不仅要在窗口右上提示,部分错误要以弹模态框的方式提示。因实例唯一,在接口不动的情况下通过继承的方式进行扩展显然是做不到的,而且单例接口变动带来的改动量也相当可观。所以功能接口功能比较稳定可封装为单例,如若不然就要为以后的功能变动买单。

猜你喜欢

转载自blog.csdn.net/u011388696/article/details/81055019