Python与设计模式–单例模式

2023-05-16

**

Python与设计模式–单例模式**

**

一、单例模式概述
保证一个类仅有一个实例,并提供一个访问它的全局访问点。

二、在Python中实现单例模式

方法一: 重写__new__方法

class Singleton1(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            # Python2类继承
            # cls._instance = super(Singleton1, cls).__new__(cls, *args, **kwargs)
            cls._instance = super().__new__(cls, *args, **kwargs)

        return cls._instance

__new__和__init__的区别:

  • __new__是object基类提供的内置的静态方方法,主要作用:
    1.在内存中为对象分配空间
    2.返回对象的引用

  • __init__是当实例对象创建完成后被调用的,设置对象属性的一些初始值,通常用在初始化一个类实例的时候,是实例方法。

方法二:使用metaclass(元类) Pyhon的高级用法

class Singleton2(type):
    def __init__(self, name, bases, dict):
        super().__init__(name, bases, dict)
        self._instance = None

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = super().__call__(*args, **kwargs)
        return self._instance

关于元类可以这样理解
python中的一切都是对象,这些对象要么是类对象的实例, 要么是元类的实例, 除了type, 元类是比较复杂的, 大多数情况下, 我们不会对类做修改。 如果需要对类做修改, 大多数情况下我们会通过:

  1. Monkey patching
  2. class decorators

方法三:使用装饰器(decorator),这是一种更加Pythonic的方法

def singleton(cls):
    instance = {}

    @functools.wraps(cls)
    def _singleton(*args, **kwargs):
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)
        return instance[cls]
    return _singleton

这里的装饰器与GoF设计模式书中的使用不一致,装饰器这个名称可能更适合在编译器领域使用,因为它会遍历并注解句法树。
在Python中,装饰器函数相当于Decorator的具体子类,而装饰器返回的内部函数相当于装饰器实例。

方法四:文件导入 :import方法 作为python的模块是天然的单例模式

class Singleton4(object):
    pass


my_singleton = Singleton4()

三、具体的例子

# -*- coding: utf-8 -*-
"""
@Time    : 2022/1/27 15:37
@Author  : ghzhou
@FileName: singleton_pattern2.py
@Software: PyCharm
"""
import threading
import time

from singleton_pattern import Singleton, singleton1, Singleton2


# VisitEntity Bus

class Bus(metaclass=Singleton2):
    lock = threading.RLock()

    def send_data(self, data):
        self.lock.acquire()
        time.sleep(3)
        print('Sending signal Data...', data)
        self.lock.release()
        print(id(self))


class VisitEntity(threading.Thread):
    my_bus = ""
    name = ""

    def get_name(self):
        return self.name

    def set_name(self, name):
        self.name = name

    def run(self):
        self.my_bus = Bus()
        self.my_bus.send_data(self.name)


if __name__ == '__main__':
    t0 = time.time()
    for i in range(3):
        print('Entity %d begin to run..' % i)
        my_entity = VisitEntity()
        my_entity.set_name('Entity_' + str(i))
        my_entity.start()

运行结果如下:
Entity 0 begin to run…
Entity 1 begin to run…
Entity 2 begin to run…
Sending signal Data… Entity_0
2345367976536
Sending signal Data… Entity_1
2345367976536
Sending signal Data… Entity_2
2345367976536
在程序运行过程中,三个线程同时运行(运行结果的前三行先很快打印出来),而后分别占用总线资源(后三行每隔3秒打印一行)。虽然看上去总线Bus被实例化了三次,但实际上在内存里只有一个实例。

四、单例模式的优缺点
单例模式的优点:
1、可以节省比较多的内存空间;
2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用;
3、单例可长驻内存,减少系统开销。
缺点:
1、 单例模式没有抽象层,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
2、单例类的职责过重,在一定程度上违背了“单一职责原则“;
3、滥用单例将带来一些负面问题,如:为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python与设计模式–单例模式 的相关文章

随机推荐