1、单例设计模式的意图
- 确保类有且只有一个对象被创建
- 为对象提供一个访问点,使程序可以全局访问对象
- 控制共享资源的并行访问
实现方式
一个简单方法就是将构造函数私有化,并创建一个静态方法来完成对象的初始化。意思就是当对象在第一次调用时被创建,此后这个类将返回同一个对象。
python实现:(因为python无法创建私有的构造函数)
class Singleton(object): # object 所有类都要继承的一个类,定义了各种魔法方法
def __new__(cls, *args, **kwargs): # cls表示类本身,self表示实例本身
if not hasattr(cls, 'instance'): # hasattr 用于判断对象是否包含对应的属性
cls.instance = super(Singleton, cls).__new__(cls) # super 用来调用父类的一个方法
return cls.instance
s = Singleton()
print(s.instance)
s1 = Singleton()
print(s1.instance)
<__main__.Singleton object at 0x0729CD90>
<__main__.Singleton object at 0x0729CD90>
2、懒汉式实例化
当我们在导入模块时,可能会无意中创建一个对象,但当时根本用不到它,会造成一种资源的浪费,这时,懒汉式实例化就能够解决这个问题,它能够确保在实际需要时才创建对象。
python实现:
class Singleton:
__instance = None
def __init__(self):
if not Singleton.__instance:
print('__init__ method called')
else:
print('Instance already created:', self.getInstance())
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
s = Singleton()
print('Object created', Singleton.getInstance())
s1 = Singleton()
__init__ method called
__init__ method called
Object created <__main__.Singleton object at 0x03693790>
Instance already created: <__main__.Singleton object at 0x03693790>
解释:在执行s = Singleton()
的时候,它会调用__init__
方法,但没有新的对象被创建,然而,实际的对象创建发生在调用Singleton.getInstance()
的时候,通过这种方法来实现懒汉式实例化。
模块级别的单例模式:
在python中,当一个模块被导入时,它就会被初始化,然而,但同一个模块被再次导入时,它不会再次初始化,因为单例模式只能有一个对象,所有,它会返回同一个对象。
3、Monostate(单态)单例模式
所有对象共享相同状态,是单例模式的变体。
class Borg:
__shared_state = {'1': '2'}
def __init__(self):
self.x = 1
self.__dict__ = self.__shared_state
pass
b = Borg()
b1 = Borg()
b.x = 4
print(Borg().__dict__)
print(b, b.__dict__)
print(b1, b1.__dict__)
{'1': '2', 'x': 4}
<__main__.Borg object at 0x02DC31F0> {'1': '2', 'x': 4}
<__main__.Borg object at 0x02DC3210> {'1': '2', 'x': 4}
解释:将类变量__shared_state
赋值给了变量__dict__
,python使用__dict__
存储一个类所有对象的状态,在上面的代码中,我们故意把__shared_state
赋给所有已经创建的实例。所以,如果我们创建了两个实例b,b1,我们将得到两个不同的对象,这一点和单例模式大为不同,后者只能生成一个对象。然而对象的状态,即b.__dict__
和b1.__dict__
却是相同的,所以b的x发生了变化,这个变化也会赋值到被所以对象共享的__dict__
变量,即b1的x也会变成4。
4、单例模式的缺点
- 由于单例模式具有全局访问权限,这是非常危险的,所有依赖于全局变量的类都会由于一个类的改变而紧密耦合为全局数据,从而可能在无意中影响另一个类
- 由于单例只创建一个对象,因此这种情况下会对同一个对象创建多个引用。
网友评论