一、理解单例设计模式
单例模式提供这样一个机制,即确保类有且只有一个特定类型的对象,并提供全局访问点。因此,单例模式通常用于日志记录、数据库操作、打印机后台处理程序;该程序运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求。由于在系统内存中只存在一个对象,因此可以节约系统资源,例如数据库操作需要频繁的创建和销毁对象时单例模式无疑可以提高系统的性能。
单例设计模式的意图:
① 确保类有且只有一个对象被创建
② 为对象提供一个访问点,以使程序可以全局访问对象
③ 控制共享资源的并行访问
实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。
利用Python实现经典的单例模式
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
s = Singleton()
s1 = Singleton()
print(s)
print(s1)
在上面的代码中,我们通过覆盖__new__方法来控制对象的创建。对象s就是由__new__方法创建的,但是在创建之前,该方法会检查对象是否已存在。
方法hasattr(python的特殊方法,用来了解对象是否具有某个属性)用于查看对象cls是否具有属性instance,该属性的作用是检查该类是否已经生成了一个对象。当对象s1被请求的时候,hasattr()发现对象已经存在,所以,对象s1将被分配已有的对象实例
单例模式中的懒汉式实例化
在导入模块的时候,我们可能无意中创建一个对象,但当时根本用不到它。懒汉式实例化能够确保在实际需要时才创建对象。所以,懒汉式实例化是一种节约资源并仅在需要时才创建它们的方式。
class Singleton(object):
__instance = None
def __init__(self):
if not Singleton.__instance:
print('__init__ method called ..')
else:
print('Instance already created:', self.get_instance())
@classmethod
def get_instance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
s = Singleton().get_instance()
s1 = Singleton().get_instance()
print(s)
print(s1)
print('....................')
s2 = Singleton()
s3 = Singleton()
print(s2)
print(s3)
在上面的代码示例中,执行s = Singleton()的时候,它会调用__init__方法,但是没有新的对象被创建。然而实际的对象创建发生在调用Singleton().get_instance()的时候,我们正是通过这种方式来实现懒汉式实例化的。
模块级别的单例模式
默认情况下,所有的模块都是单例,这是由Python的导入行为所决定的。
python通过下列的方式来工作:
① 检查一个python模块是否已经导入
② 如果已经导入,则返回该模块的对象,如果还没有导入,则导入该模块,并实例化
③ 因此,当模块被导入的时候,它就会被初始化。然而,当同一个模块被再次导入的时候,它不会再次初始化,因为单例模式只能有一个对象,所以,它会返回同一个对象
Monostate单例模式
在GOF(设计模式)中的单例设计模式是指,一个类有且只有一个对象。通常程序员需要的是让实例共享相同的状态。开发人员应该关注状态和行为,而不是同一性。由于该概念及与所有对象共享相同的状态,因此被称为单态模式。
Monostate 模式可以通过Python轻松实现,在下面的代码中,我们将类变量__shared_state赋给了变量__dict__。Python使用__dict__存储一个类所有对象的状态。
class Borg(object):
__shared_state = {"1": "2"}
def __init__(self):
self.x = 1
self.__dict__ = self.__shared_state
b = Borg()
b1 = Borg()
b.x = 4
print("Borg Object b: ", b)
print("Borg Object b1: ", b1)
print("Object state b: ", b.__dict__)
print("Object state b1: ", b1.__dict__)
在上面的代码中,我们把__shared_state赋给所有已经创建的实例。所以我们创建了两个实例“b”和“b1”,我们得到了两个不同的对象,这一点和单例模式是不同的,单例模式只能生成一个对象。然而对象的状态即b.__dict__和b1.__dict__却是相同的;就算对象b的变量x发生了变化,这个变化也会复制到所有对象共享的__dict__中
单例和元类
用来创建类的类就是元类。元类是一个类的类,意味着该类是它的元类的实例。使用元类,程序员有机会从预定义的Python类创建自己类型的类。例如,如果你有一个对象MyClass,你可以创建一个元类MyKls,它按照你需要的方式重新定义MyClass的行为
类的定义是由它的元类决定,所以当我们用类A创建一个类时,Python通过A=type(name, bases, dict)创建它
name:这是类的名称 bases:这是基类 dict: 这是属性变量
现在如果有一个类有一个预定义的元类,那么python就会通过A=MetaKls(name, bases, dict)来创建类;
下面python3中一个示例元类的实现:
class MyInt(type):
def __call__(cls, *args, **kwargs):
print("here's My int", args)
print("想怎么处理这个对象就怎么处理")
return type.__call__(cls, *args, **kwargs)
class Int(metaclass=MyInt):
def __init__(self, x, y):
self.x = x
self.y = y
i = Int(4, 5)
对于已经存在的类来说,当需要创建对象时,将调用Python的特殊方法__call__。在上面的代码中,当我们使用int(4,5)实例化int类时,MyInt元类的__call__方法将被调用,这意味着现在元类控制着对象的实例变化。
前面的思路同样适用于单例设计模式。由于元类对类的创建和对象实例化有更多的控制权,所以它可以用于创建单例。(注意:为了控制类的创建和初始化,元类将覆盖__new__和__init__方法)
下面代码基于元类的单例实现:
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(metaclass=MetaSingleton):
pass
log1 = Logger()
log2 = Logger()
print(log1, log2)