暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

设计模式:Singleton(单例)模式

猿武场 2021-06-28
423

「 设计模式 」可复用面向对象软件的基础
  整理 | 猿胖子
  出品 | 猿武场(ID:apesarena)

关注公众号并回复数字「 1024 」加入猿武场微信社群 

设计面向对象软件比较困难,而设计可复用的面向对象软件就更加困难。我们也都知道不是所有问题都要重复造轮子,更好的方式是复用之前使用的解决方案。设计模式使我们可以更加简单方便地复用成功的设计和体系结构,避免设计损害系统复用性。

本系列文章中所讲解的设计模式均采用C++语言表述。

概念与意图
保证一个类仅有一个实例,并且提供一个访问它的全局访问点。
使用场景

对于某些类来说,只有一个实例是很重要的。例如如下某些场景:

  • 系统中可以有多个打印机,但却只应该有一个printer spooler (打印假脱机) ,以避免两个打印作业同时输出到打印机

  • 系统中只应该有一个文件系统和一个窗口管理器

  • 应用软件系统中的日志应用,保证仅有一个实例去操作


怎么样才能保证一个类只有一个实例并且这个实例易于被访问呢?全局变量使得一

个对象可以被访问,但它不能防止我们实例化多次这个对象。


一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求),并且它可以提供一个访问改实例的方法。这就是 SingIeton(单例)模式
适用性

在如下情况下可以使用 SingIeton(单例模式

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

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

参与者
  • 定义一个 Instance 操作,允许客户访问它的唯一实例。 Instance 是一个类的中的一个静态成员函数

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

SingIeton(单例)模式优点
  • 对唯一实例的受控访问    因为 Singleton 类封装它的唯一实例,所以它可以严格的控制客户怎样以何时访问它

  • 允许对操作和表示的精化     Singleton 可以有子类,而且用这个扩展类的实例来配置一个应用非常容易

  • 允许可变数目的实例    这个模式使得我们更易于改变想法,并 允许 Singleton 的多个实例。此外,我们还可以用相同的方法来控制应用所使用的实例数目。只有允许访问 Singleton 的操作需要改变

  • 比类操作更灵活    另一种封装单例功能的方式是使用类操作(即C++中的静态成员函数)。但这种设计难以改变设计以允许一个类有多个实例,此外C++中的静态成员函数不是虚函数,其子类不能多态地重定义


具体实现

在使用 SingIeton(单例)模式时所需要考虑的实现问题是保证一个唯一的实例。做到这一点的一个常用方法是将创建这个实例的操作隐藏在一个类操作(即一个静态成员函数或者是一个类方法)后面,由它保证只有一个实例被创建。


// singleton.h

class Singleton : public QObject
{
    Q_OBJECT
public:
    static Singleton* Instance();
protected:
    explicit Singleton(QObject *parent = nullptr);
public:
    void test();

privatestatic Singleton* _instance;

signals:

};

// singleton.cpp


Singleton* Singleton::_instance = 0;

Singleton *Singleton::Instance()
{
    if(_instance == 0){
        _instance = new Singleton;
    }
    return  _instance;
}

void Singleton::test()
{
    qDebug() <<" this is test !";

}

// to test

 Singleton::Instance()->test();




在QT中的另一种实现

使用QT提供的宏 Q_GLOBAL_STATIC 可以方便地创建线程安全的全局静态对象


// singleton.h

class Singleton : public QObject
{
    Q_OBJECT
public:
    static Singleton* Instance();
public:
    explicit Singleton(QObject *parent = nullptr);
public:
    void test();

signals:

};

// singleton.cpp

#include <QGlobalStatic>

Q_GLOBAL_STATIC(Singleton,singleton)
Singleton *Singleton::Instance()
{

    return  singleton();
}

void Singleton::test()
{
    qDebug() <<
" this is test !";

}

// to test

 Singleton::Instance()->test();





需要注意将 Q_GLOBAL_STATIC 宏放置于源文件且非函数体中,否则会编译错误。由于生成的对象具有静态链接,如被多个源文件包含将导致被多次定义。


注公众号并回复数字「 1024 」加入猿武场微信社群 

欢迎加入程序员社群,更多技术摘要等你拿走

社群福利:

1. 行业大牛技术手札,知识点汇总

2. 求职/招聘信息内推

4. 人际交往,增强技术宅人际交流;

5. 调节繁杂无趣的闲暇时光;

6. 不定期线上周边线下技术活动沙龙


代 码 改 / 变 / 世 / 界
感谢您对猿武场的关注与支持


文章转载自猿武场,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论