@rfish
2015-07-18T13:05:45.000000Z
字数 3341
阅读 1482
实验楼
确保只有一个对象实例存在,所有的信息都从这个对象获取
单例模式的实现只需要找一个变量存放创建的实例,然后每次获取实例时,先检查变量中是否已保存实例,如果没有则创建一个实例并将其存放到变量中,以后都从这个变量中获取实例就可以了。单例模式中,只会创建一次实例。
_A
不是Singleton
# -*- coding: utf-8 -*-
class Singleton(object):
"""
单例模式
"""
class _A(object):
"""
真正干活的类, 对外隐藏
"""
def __init__(self):
pass
def display(self):
""" 返回当前实例的 ID,是全局唯一的"""
return id(self)
# 类变量,用于存储 _A 的实例
_instance = None
def __init__(self):
""" 先判断类变量中是否已经保存了 _A 的实例,如果没有则创建一个后返回"""
if Singleton._instance is None:
Singleton._instance = Singleton._A()
def __getattr__(self, attr):
""" 所有的属性都应该直接从 Singleton._instance 获取"""
return getattr(self._instance, attr)
if __name__ == '__main__':
# 创建两个实例
s1 = Singleton()
s2 = Singleton()
print(id(s1), s1.display())
print(id(s2), s2.display())
类变量与实例变量:
类变量
是所有对象共有
,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量
则属对象私有
,某一个对象将其值改变,不影响其他对象解释
在上面的代码中由于
内置类
是在__init__
中实例化,而只有当类变量_instance
为None时才会实例化。而只有第一次执行时,才为None(因为_instance
是类变量即所有对象共享,在第二次实例类的时候,是不为None的)所以类_A是永远只有一个实例的。
# -*- coding: utf-8 -*-
class Singleton:
"""
单例类装饰器,可以用于想实现单例的任何类。注意,不能用于多线程环境。
"""
def __init__(self, cls):
""" 需要的参数是一个类 """
self._cls = cls
def Instance(self):
"""
返回真正的实例
"""
try:
return self._instance
except AttributeError:
self._instance = self._cls()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `Instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
# 装饰器
@Singleton
class A:
"""一个需要单列模式的类"""
def __init__(self):
pass
def display(self):
return id(self)
if __name__ == '__main__':
s1 = A.Instance()
s2 = A.Instance()
print(s1, s1.display())
print(s2, s2.display())
print(s1 is s2)
- 装饰器
- 看不懂
# -*- coding: utf-8 -*-
import sqlite3
from flask import current_app
from flask import _app_ctx_stack as stack
class SQLite3(object):
def __init__(self, app=None):
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
""" 典型的 Flask 扩展的初始化方式"""
app.config.setdefault('SQLITE3_DATABASE', ':memory:')
app.teardown_appcontext(self.teardown)
def connect(self):
""" 连接到 sqlite 数据库"""
return sqlite3.connect(current_app.config['SQLITE3_DATABASE'])
def teardown(self, exception):
""" 关闭 sqlite 链接"""
ctx = stack.top
if hasattr(ctx, 'sqlite3_db'):
ctx.sqlite3_db.close()
@property
def connection(self):
""" 单例模式在这里:使用 flask._app_ctx_stack 存放 sqlite 链接,
每次获取数据库链接时都通过 connection 获取"""
ctx = stack.top
# 判断 ctx 中是否已经包含了sqlite 链接
if ctx is not None:
if not hasattr(ctx, 'sqlite3_db'):
# 如果没有的话,才创建, 这一步操作只会发生一次
ctx.sqlite3_db = self.connect()
return ctx.sqlite3_db
一个函数,传入需要创建的产品类型,然后返回相应的产品就行了。(但是只能返回一个产品)
在创建
父类工厂抽象类
中,定义多个方法。在后面的工厂类中继承
该类,并重写
方法,就可以返回两个以及以上的产品
问题1:
在学习单例模式时,我们实现了两种单例模式,并且还看到了单例模式在 Flask 扩展中的使用。但是似乎我们实现的单例模式不能再多线程环境中工作?你能用 Python实现一个能在多线程环境中正常工作的单例模式吗?并给出测试代码。
解答:
单例模式看了实验手册还是不怎么明白,上网查询后看到多线程使用加锁-双重锁定
有两个多线程的线程单例模式:饿汉式单例类
懒汉式单例类
实例代码:
#encoding=utf-8
#单例模式
def PrintInfo(info):
print info.decode('utf-8').encode('utf-8')
import threading
#单例类
class Singleton():
instance=None
mutex=threading.Lock()
def _init__(self):
pass
@staticmethod
def GetInstance():
if(Singleton.instance==None):
Singleton.mutex.acquire()
if(Singleton.instance==None):
PrintInfo('初始化实例')
Singleton.instance=Singleton()
else:
PrintInfo('单例已经实例化')
Singleton.mutex.release()
else:
PrintInfo('单例已经实例化')
return Singleton.instance
def clientUI():
Singleton.GetInstance()
Singleton.GetInstance()
Singleton.GetInstance()
return
if __name__=='__main__':
clientUI();
问题2:
虽然抽象工厂模式解决了工厂方法模式中遇到的问题,但是抽象工厂模式也是有缺陷的,你能总结下抽象工厂优缺点吗?
解答:
优点:
1.增加新的产品的时候很方便,只需要增加对应的代码,而不需要修改原有代码。
2.从抽象的角度去看,使用的时候,永远只需要从一个入口去取我们需要的产品。
缺点:
每次修改代码的时候,还是需要修改两个地方,一个是父类抽象工厂,需要增加对应的接口,然后是在继承父类的类中复写对应的接口。