别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2025 面试记录
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2025 面试记录
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 辨析

  • Sockets编程

  • Django

  • stackoverflow

  • Flask

  • 全栈之路

  • 面试

  • 代码片段

  • 异步编程

  • 😎Awesome资源

  • PEP

  • Python工匠系列

  • 高阶知识点

  • Python 学习资源待整理
  • 设计模式

    • Python 设计模式
    • 装饰器模式
    • 抽象工厂模式
    • 建造者模式/生成器模式
    • 原型模式
    • 单例模式
      • 意图
      • 问题
      • 解决方案
      • 真实世界类比
      • 单例模式结构
      • 单例模式适合应用场景
      • 实现方式
      • 单例模式优缺点
        • 优点
        • 缺点
      • 与其他模式的关系
      • 基本思想和原则
      • 动机
      • 单例模式存在意义
      • 实例代码
    • 设计模式(2)——工厂方法模式
    • 设计模式(3)——抽象工厂模式
    • 设计模式(4)——模板方法模式
    • 设计模式(5)——代理模式
    • 设计模式(6)——建造者模式
    • 设计模式(7)——策略模式
    • 设计模式(8)——命令模式
    • 设计模式(9)——原型模式
    • 设计模式(10)——中介者模式
    • 设计模式(11)——责任链模式
    • 设计模式(12)——装饰器模式
    • 设计模式(13)——适配器模式
    • 设计模式(14)——迭代器模式
    • 设计模式(15)——观察者模式
    • 设计模式(16)——外观模式
    • 设计模式(17)——状态模式
    • 设计模式(18)——桥接模式
    • 设计模式(19)——享元模式
    • 设计模式(20)——解释器模式
    • 设计模式(21)——组合模式
    • 设计模式(23)——备忘录模式
    • Python 全栈之路系列之单例设计模式
    • 设计模式(22)——访问者模式
    • 工厂方法模式
    • Python 设计模式资源收集
  • 好“艹蛋”的 Python 呀!
  • FIFO | 待学清单📝
  • pip 安装及使用
  • 数据分析

  • 源码阅读计划

  • OOP

  • 关于 python 中的 setup.py
  • 并行分布式框架 Celery
  • 七种武器,让你的代码提高可维护性
  • 使用 pdb 调试 Python 代码
  • 每周一个 Python 标准库
  • 🐍Python
  • 设计模式
佚名
2017-12-05
目录

单例模式

# 意图

单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

单例模式

# 问题

单例模式同时解决了两个问题, 所以违反了单一职责原则:

  1. 保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例数量? 最常见的原因是控制某些共享资源 (例如数据库或文件) 的访问权限。

    它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的对象, 而不是一个新对象。

    注意, 普通构造函数无法实现上述行为, 因为构造函数的设计决定了它必须总是返回一个新对象。

一个对象的全局访问节点

客户端甚至可能没有意识到它们一直都在使用同一个对象。

  1. 为该实例提供一个全局访问节点。 还记得你 (好吧, 其实是我自己) 用过的那些存储重要对象的全局变量吗? 它们在使用上十分方便, 但同时也非常不安全, 因为任何代码都有可能覆盖掉那些变量的内容, 从而引发程序崩溃。

    和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码覆盖。

    还有一点: 你不会希望解决同一个问题的代码分散在程序各处的。 因此更好的方式是将其放在同一个类中, 特别是当其他代码已经依赖这个类时更应该如此。

如今,单例模式已经变得非常流行,以至于人们会将只解决上文描述中任意一个问题的东西称为单例。

# 解决方案

所有单例的实现都包含以下两个相同的步骤:

  • 将默认构造函数设为私有, 防止其他对象使用单例类的 new运算符。
  • 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

如果你的代码能够访问单例类, 那它就能调用单例类的静态方法。 无论何时调用该方法, 它总是会返回相同的对象。

# 真实世界类比

政府是单例模式的一个很好的示例。 一个国家只有一个官方政府。 不管组成政府的每个人的身份是什么, “某政府” 这一称谓总是鉴别那些掌权者的全局访问节点。

# 单例模式结构

单例模式结构

单例 (Singleton) 类声明了一个名为 getInstance获取实例的静态方法来返回其所属类的一个相同实例。

单例的构造函数必须对客户端 (Client) 代码隐藏。 调用 获取实例方法必须是获取单例对象的唯一方式。

# 单例模式适合应用场景

如果程序中的某个类对于所有客户端只有一个可用的实例,可以使用单例模式。

单例模式禁止通过除特殊构建方法以外的任何方式来创建自身类的对象。该方法可以创建一个新对象,但如果该对象已经被创建,则返回已有的对象。

如果你需要更加严格地控制全局变量,可以使用单例模式。

单例模式与全局变量不同,它保证类只存在一个实例。除了单例类自己以外,无法通过任何方式替换缓存的实例。

请注意,你可以随时调整限制并设定生成单例实例的数量,只需修改 获取实例方法,即 getInstance 中的代码即可实现。

# 实现方式

  1. 在类中添加一个私有静态成员变量用于保存单例实例。

  2. 声明一个公有静态构建方法用于获取单例实例。

  3. 在静态方法中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。

  4. 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。

  5. 检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用。

# 单例模式优缺点

# 优点

  • 你可以保证一个类只有一个实例。
  • 你获得了一个指向该实例的全局访问节点。
  • 仅在首次请求单例对象时对其进行初始化。

# 缺点

  • 违反了单一职责原则。该模式同时解决了两个问题。
  • 单例模式可能掩盖不良设计,比如程序各组件之间相互了解过多等。
  • 该模式在多线程环境下需要进行特殊处理,避免多个线程多次创建单例对象。
  • 单例的客户端代码单元测试可能会比较困难,因为许多测试框架以基于继承的方式创建模拟对象。由于单例类的构造函数是私有的,而且绝大部分语言无法重写静态方法,所以你需要想出仔细考虑模拟单例的方法。要么干脆不编写测试代码,或者不使用单例模式。

# 与其他模式的关系

  • 外观模式 (opens new window)类通常可以转换为单例模式 (opens new window)类, 因为在大部分情况下一个外观对象就足够了。

  • 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元模式 (opens new window)就和单例 (opens new window)类似了。 但这两个模式有两个根本性的不同。

    1. 只会有一个单例实体, 但是_享元_类可以有多个实体, 各实体的内在状态也可以不同。
    2. _单例_对象可以是可变的。 享元对象是不可变的。
  • 抽象工厂模式 (opens new window)、 生成器模式 (opens new window)和原型模式 (opens new window)都可以用单例 (opens new window)来实现。

# 基本思想和原则

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

单例模式有以下三个要素:

  1. 保证类实例的唯一性。
  2. 提供一个获取类唯一实例的全局访问点。
  3. 类必须自行创建这个唯一的实例,不能由用户手动创建。

# 动机

在一些情况下我们希望某个类在系统中有且仅有一个实例,常见的例子有全局 id 生成器、任务管理器、全局计时器、配置对象等。如果这些类的对象有多个,可能造成数据不一致的情况,因此需要一种通用的模式来保证这些类在系统中有且仅有一个实例。

# 单例模式存在意义

模式特点:

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

  1. 设计模式在所有语言内都是通用的
  2. 设计模式存在的意义就是让代码设计结构设计的更好

# 实例代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from wsgiref.simple_server import make_server

class ConnectionPool:

    __instance = None

    def __init__(self):
        self.ip = "1.1.1.1"
        self.port = 3306
        self.pwd = "123123"
        self.username = 'xxxx'
        # 去连接
        self.conn_list = [1,2,3,4,5,6,7,8,9,10]

    @staticmethod
    def get_instance():
        if ConnectionPool.__instance:
            return ConnectionPool.__instance
        else:
            # 创建一个对象,并将对象赋值给静态字段 __instance
            ConnectionPool.__instance = ConnectionPool()
            return ConnectionPool.__instance

    def get_connection(self):
        # 获取连接
        import random
        r = random.randrange(1,11)
        return r

def index():
    # p = ConnectionPool()
    # print(p)
    p = ConnectionPool.get_instance()
    conn = p.get_connection()
    return "iiiiiii" + str(conn)

def news():
    return 'nnnnnnn'

def RunServer(environ, start_response):
    start_response(status='200 OK', headers=[('Content-Type', 'text/html')])

    url = environ['PATH_INFO']
    if url.endswith('index'):
        ret = index()
        return ret
    elif url.endswith('news'):
        ret = news()
        return ret
    else:
        return "404"

if __name__ == '__main__':
    httpd = make_server('', 80, RunServer)
    print("Serving HTTP on port 80...")
    httpd.serve_forever()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

单例模式的实现可以分为懒汉式和饿汉式两种,懒汉式指的是等到需要的时候再创建对象,饿汉式则是在类被加载时就创建一个对象。因此懒汉式存在线程安全的问题,而饿汉式没有线程安全问题。

编辑 (opens new window)
#创建型模式#工厂方法模式#单例模式
上次更新: 2024-07-23, 01:00:43
原型模式
设计模式(2)——工厂方法模式

← 原型模式 设计模式(2)——工厂方法模式→

最近更新
01
2025 面试记录
05-28
02
提升沟通亲和力的实用策略
03-26
03
工作
07-15
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式