**
Python与设计模式–单例模式**
**
一、单例模式概述 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
二、在Python中实现单例模式
方法一: 重写__new__方法
class Singleton1(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
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, 元类是比较复杂的, 大多数情况下, 我们不会对类做修改。 如果需要对类做修改, 大多数情况下我们会通过:
- Monkey patching
- 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()
三、具体的例子
"""
@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
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、滥用单例将带来一些负面问题,如:为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;
|