设计模式:单例模式

1 概述

想想一下这个场景,一个系统中可以存在多个打印任务,但是只有一个正在工作的任务。我们怎样才能保证一个类只有一个实例并且这个实例易于被访问呢?一个全局变量可以使得一个对象可以被访问,但是不能防止实例化多个对象。

一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个方位该实例的方法,这就是单例模式的动机。

单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个 系统提供这个实例,这个类称为单例类,它提供全局访问的方法 。单例模式又名单件模式单态模式

单例模式的要点:

  • 某个类只能有一个实例
  • 它必须自行创建这个实例
  • 它必须自行向整个系统提供这个实例。

2 图解

此模式太简单,没有图。

单例模式包含如下角色:

  • Singleton:单例

3 优缺点

优点:

  • 提供了对唯一实例的受控访问。
  • 缩小命名空间。Singleton模式是对全局变量的一种改进。它避免了那些存储唯一实例的 全局变量污染名空间。
  • 由于只存在一个实例,可以节约系统资源。
  • 允许可变数量的实例。

缺点:

  • 没有抽象层,拓展会有很大困难。
  • 单例类职责过重,在一定程度上违背了“单一原则”。

4 应用场景

在以下情况下可以使用抽象工厂模式:

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

5 实例

Singleton_Uml

5.1 C++实现

  • singleton.h
#ifndef SINGLETON_H
#define SINGLETON_H

#include <iostream>
using namespace std;

class Singleton
{
protected:
    Singleton();

public:
    static Singleton* Instance();

private:
    static Singleton* _instance;
};

#endif // SINGLETON_H
  • singleton.cpp
#include "singleton.h"
#include <iostream>

using namespace std;

Singleton* Singleton::_instance = 0;

Singleton::Singleton()
{
    cout << "==> Singleton." << endl;
}

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

    return _instance;
}
  • main.cpp
#include "singleton.h"
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    Singleton* singleton1 = Singleton::Instance();
    Singleton* singleton2 = Singleton::Instance();

    if (singleton1 == singleton2)
        cout << "They equal." << endl;
    return 0;
}

运行结果:

==> Singleton.
They equal.

代码说明:

客户仅通过 Instance() 成员函数访问这个单例。变量 _instance 初始化为0,而静态成员函数 Instance() 使用惰性初始化;它的返回值直到被第一次访问时才创建和保存。

注意构造器是保护型的。试图直接实例化 Singleton 的客户将得到一个编译时的错误信息。 这就保证了仅有一个实例可以被创建。 比如,我们使用如下代码实例化:

 Singleton* singleton = new Singleton();

编译器会报出如下错误:

E:\Programming\Design Patterns\Code\C++\04_Singleton\singleton.h:10: error: 'Singleton::Singleton()' is protected
     Singleton();
     ^

5.2 Python代码

#-*- coding: utf-8 -*-

'''
  单例模式
'''
class Singleton(object):
    _instance = None       

    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  
            print('==>Singleton')
        return cls._instance  

def main():
    singleton1 = Singleton()
    singleton2 = Singleton()
    print(singleton1 is singleton2)

if __name__ == '__main__':
    main()

运行结果:

==>Singleton
True

代码分析:

在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance。最后print(singleton1 is singleton2)结果为Ture,说明singleton1与singleton2为同一实例。

系列推荐阅读:

  • 设计模式:简单工厂模式
  • 设计模式:工厂方法模式
  • 设计模式:抽象工厂模式

原文发布于微信公众号 - C与Python实战(CPythonPractice)

原文发表时间:2018-04-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿人谷

mybatis调用视图和存储过程

    现在的项目是以Mybatis作为O/R映射框架,确实好用,也非常方便项目的开发。MyBatis支持普通sql的查询、视图的查询、存储过程调用,是一种非常...

33250
来自专栏开发

mysql学习之优化总结(2)--索引的那些事

上一篇文章我们在研究MySQL查询过程的查询优化步骤中提到过优化索引可以优化查询优化的过程,索引到底是什么?它在查询过程中是一个怎样的角色?索引适用于什么场景?...

22450
来自专栏后端技术探索

mysql5.7强势支持原生json格式!!全面掌握

mysql一直是如此优秀,但是随着最近一些nosql的强劲发展,甚为关系型数据库的mysql,也不例外在某些层面稍有逊色。其中,是否支持json格式是最常被用来...

10720
来自专栏加米谷大数据

Hive的数据类型

本文介绍hive的数据类型,数据模型以及文件存储格式。这些知识大家可以类比关系数据库的相关知识。

18720
来自专栏开源优测

AutoLine源码分析之数据库模型

AutoLine开源平台是一个开源自动化测试解决方案,基于RobotFramework进行二次开发,支持RobotFramework几乎所有的库。

10410
来自专栏java系列博客

单例模式的各种实现

21460
来自专栏北京马哥教育

10分钟学会理解和解决MySQL乱码问题

本文将详细介绍MySQL乱码的成因和具体的解决方案。在阅读本文之前,强烈建议对字符集编码概念还比较模糊的同学 阅读下博主之前对相关概念的一篇科普:十分钟搞清字符...

31680
来自专栏影子

oracle行转列、列转行、连续日期数字实现方式及mybatis下实现方式

-- 行转列 SELECT * from ( SELECT tt1.SAP_ID,TT1.dt,TT1.EFF from ( SELECT t1.SAP...

51520
来自专栏西枫里博客

rand()随机的效率问题

在平时开发过程中,数据量不超过1W条的,通常执行随机查询是通过对order进行rand操作的进行的。但是随着数据量的增加,rand严重制约了整站的访问速度。...

6110
来自专栏禹都一只猫博客

Python的flask:models.py来创建mysql数据库

1.4K90

扫码关注云+社区

领取腾讯云代金券