[关闭]
@rfish 2015-07-18T13:05:45.000000Z 字数 3341 阅读 1482

创建型模式

实验楼


单例模式

确保只有一个对象实例存在,所有的信息都从这个对象获取

单例模式的实现只需要找一个变量存放创建的实例,然后每次获取实例时,先检查变量中是否已保存实例,如果没有则创建一个实例并将其存放到变量中,以后都从这个变量中获取实例就可以了。单例模式中,只会创建一次实例。

  1. # -*- coding: utf-8 -*-
  2. class Singleton(object):
  3. """
  4. 单例模式
  5. """
  6. class _A(object):
  7. """
  8. 真正干活的类, 对外隐藏
  9. """
  10. def __init__(self):
  11. pass
  12. def display(self):
  13. """ 返回当前实例的 ID,是全局唯一的"""
  14. return id(self)
  15. # 类变量,用于存储 _A 的实例
  16. _instance = None
  17. def __init__(self):
  18. """ 先判断类变量中是否已经保存了 _A 的实例,如果没有则创建一个后返回"""
  19. if Singleton._instance is None:
  20. Singleton._instance = Singleton._A()
  21. def __getattr__(self, attr):
  22. """ 所有的属性都应该直接从 Singleton._instance 获取"""
  23. return getattr(self._instance, attr)
  24. if __name__ == '__main__':
  25. # 创建两个实例
  26. s1 = Singleton()
  27. s2 = Singleton()
  28. print(id(s1), s1.display())
  29. print(id(s2), s2.display())
  • 类变量与实例变量:

    类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象

  • 解释

    在上面的代码中由于内置类是在__init__中实例化,而只有当类变量_instanceNone时才会实例化。而只有第一次执行时,才为None(因为_instance是类变量即所有对象共享,在第二次实例类的时候,是不为None的)所以类_A是永远只有一个实例的。

  1. # -*- coding: utf-8 -*-
  2. class Singleton:
  3. """
  4. 单例类装饰器,可以用于想实现单例的任何类。注意,不能用于多线程环境。
  5. """
  6. def __init__(self, cls):
  7. """ 需要的参数是一个类 """
  8. self._cls = cls
  9. def Instance(self):
  10. """
  11. 返回真正的实例
  12. """
  13. try:
  14. return self._instance
  15. except AttributeError:
  16. self._instance = self._cls()
  17. return self._instance
  18. def __call__(self):
  19. raise TypeError('Singletons must be accessed through `Instance()`.')
  20. def __instancecheck__(self, inst):
  21. return isinstance(inst, self._decorated)
  22. # 装饰器
  23. @Singleton
  24. class A:
  25. """一个需要单列模式的类"""
  26. def __init__(self):
  27. pass
  28. def display(self):
  29. return id(self)
  30. if __name__ == '__main__':
  31. s1 = A.Instance()
  32. s2 = A.Instance()
  33. print(s1, s1.display())
  34. print(s2, s2.display())
  35. print(s1 is s2)

  1. # -*- coding: utf-8 -*-
  2. import sqlite3
  3. from flask import current_app
  4. from flask import _app_ctx_stack as stack
  5. class SQLite3(object):
  6. def __init__(self, app=None):
  7. self.app = app
  8. if app is not None:
  9. self.init_app(app)
  10. def init_app(self, app):
  11. """ 典型的 Flask 扩展的初始化方式"""
  12. app.config.setdefault('SQLITE3_DATABASE', ':memory:')
  13. app.teardown_appcontext(self.teardown)
  14. def connect(self):
  15. """ 连接到 sqlite 数据库"""
  16. return sqlite3.connect(current_app.config['SQLITE3_DATABASE'])
  17. def teardown(self, exception):
  18. """ 关闭 sqlite 链接"""
  19. ctx = stack.top
  20. if hasattr(ctx, 'sqlite3_db'):
  21. ctx.sqlite3_db.close()
  22. @property
  23. def connection(self):
  24. """ 单例模式在这里:使用 flask._app_ctx_stack 存放 sqlite 链接,
  25. 每次获取数据库链接时都通过 connection 获取"""
  26. ctx = stack.top
  27. # 判断 ctx 中是否已经包含了sqlite 链接
  28. if ctx is not None:
  29. if not hasattr(ctx, 'sqlite3_db'):
  30. # 如果没有的话,才创建, 这一步操作只会发生一次
  31. ctx.sqlite3_db = self.connect()
  32. return ctx.sqlite3_db

工厂模式家族

简单工厂模式

一个函数,传入需要创建的产品类型,然后返回相应的产品就行了。(但是只能返回一个产品)

抽象工厂模式

在创建父类工厂抽象类中,定义多个方法。在后面的工厂类中继承该类,并重写方法,就可以返回两个以及以上的产品


作业

问题1:
在学习单例模式时,我们实现了两种单例模式,并且还看到了单例模式在 Flask 扩展中的使用。但是似乎我们实现的单例模式不能再多线程环境中工作?你能用 Python实现一个能在多线程环境中正常工作的单例模式吗?并给出测试代码。

解答:

单例模式看了实验手册还是不怎么明白,上网查询后看到多线程使用加锁-双重锁定有两个多线程的线程单例模式:饿汉式单例类 懒汉式单例类

实例代码:

  1. #encoding=utf-8
  2. #单例模式
  3. def PrintInfo(info):
  4. print info.decode('utf-8').encode('utf-8')
  5. import threading
  6. #单例类
  7. class Singleton():
  8. instance=None
  9. mutex=threading.Lock()
  10. def _init__(self):
  11. pass
  12. @staticmethod
  13. def GetInstance():
  14. if(Singleton.instance==None):
  15. Singleton.mutex.acquire()
  16. if(Singleton.instance==None):
  17. PrintInfo('初始化实例')
  18. Singleton.instance=Singleton()
  19. else:
  20. PrintInfo('单例已经实例化')
  21. Singleton.mutex.release()
  22. else:
  23. PrintInfo('单例已经实例化')
  24. return Singleton.instance
  25. def clientUI():
  26. Singleton.GetInstance()
  27. Singleton.GetInstance()
  28. Singleton.GetInstance()
  29. return
  30. if __name__=='__main__':
  31. clientUI();

问题2:
虽然抽象工厂模式解决了工厂方法模式中遇到的问题,但是抽象工厂模式也是有缺陷的,你能总结下抽象工厂优缺点吗?

解答:

优点:
1.增加新的产品的时候很方便,只需要增加对应的代码,而不需要修改原有代码。
2.从抽象的角度去看,使用的时候,永远只需要从一个入口去取我们需要的产品。
缺点:
每次修改代码的时候,还是需要修改两个地方,一个是父类抽象工厂,需要增加对应的接口,然后是在继承父类的类中复写对应的接口。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注