单例

当一个类只能有一个实例,并且需要提供一个全局访问点时,就可以使用单例模式来定义类。

在Python中单例有多种定义方式,这里选取最简单的一种定义和使用修饰器的线程安全的定义方式进行举例。

首先看最简单的定义方式。

class Singleton(object):
	def __new__(cls, *args, **kwargs):
		if not hasattr(cls, '_instance'):
			org = super(Singleton, cls)
			cls._instance = org.__new__(cls, *args, **kwargs)
		return cls._instance


class Factory(Singleton):
	def __init__(self, name):
		self.name = name
	
	def __str__(self):
		return self.name


obj1 = Factory("Fac1")
print(id(obj1))
obj2 = Factory("Fac2")
print(id(obj2))

最简单的定义方式定义出的单例类面临最大的问题就是线程安全,当有两个或以上的线程同时对单例类实例进行操作时,就可能会出现不可预知的潜在问题。所以使用线程安全的单例定义会更加稳妥。这里会先使用后文才会介绍到的线程,具体多线程处理的内容可参考后面的章节。

import functools
import threading


def singleton(cls):
	""" 用于标记单例类的修饰器 """

	cls.__new_original__ = cls.__new__

	@functools.wraps(cls.__new__)
	def singleton_new(cls, *args, **kw):
		it = cls.__dict__.get('__it__')
		if it is not None:
			return it

		cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
		it.__init_original__(*args, **kw)
		return it
	
	cls.__new__ = singleton_new
	cls.__init_original__ = cls.__init__
	cls.__init__ = object.__init__
	
	return cls


def synchronized(func):
	""" 为普通函数增加线程同步功能的修饰器 """

	func.__lock__ = threading.Lock()
	
	def synced_func(*args, **kwargs):
		with func.__lock__:
			return func(*args, **kwargs)
	
	return synced_func


@singleton
class ProgramState:
	
	__activated = False
	
	def __init__(self):
		self.__activated = False
	
	@property
	def activated(self):
		return self.__activated
		
	@synchronized
	@activated.setter
	def activated(self, value):
		self.__activated = value