# -*- coding: utf-8 -*-
__author__ = ‘Administrator‘
#python高级编程:有用的设计模式
#设计械是可复用的,某种程序上它对软件设计中觉问题提供的语言相关解决识方案,最近最流行的书籍:
"""
gamma、heim、johson和vlissides a.k.a"四人组(gof)"编写的elements of reusable object-oriented software(中文:<设计模式:可复用面向对象软件基础>)
它被认为这个领域中重要作品
python提供了3种设计模式:
"""
#创建型模式:用于生成具有特定行为的对象模式
"""它提供了实例化机制,它可以是一个特殊的对象工厂甚至类工厂,这在比如x之类的编译型 语言中很重要的模式,因为在运行时按照要求生成类型更加困难
,但是在python中,这些是内建的,比如type,可以通过代码来定义新的类型,如下:"""
mytext=type(‘mytyper‘,(object,),{‘a‘:1})
ob=mytext()
print type(ob)
print ob.a
print isinstance(ob,object)
"""
类和类型是内建工厂,这些功能是实现工厂设计模式的基础
除了工厂之外,python中gof的唯一有趣的创建模式是单例模式(singleton)
"""
#单例模式:用来限制一个类只能实例化为一个对象
"""
单例模式确保给定的类在应用程序中始终只存在一个实例.例如:当希望限制一个资源在进程中访问一个并且只有一个内在上下文的时候,就可以使用它
举个例子:一个数据库连接器类就是一个单例,在内存中处理同步并其数据,它假设没有其他实例同时与数据库交互。
这个模式可以大大简化应用程序中并发的处理,为整个应用程序满园提供功能的实用程序往往被声明为单例,通过 以下例子解释这个
使用__new__方法,如下:
"""
class A(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls,‘_instance‘):
orig=super(A,cls)
cls._instance=orig.__new__(cls,*args,**kwargs)
return cls._instance
class B(A):
a=1
one=B()
two=B()
two.a=3
print one.a
#不过这种模式子类化方面也存在一些问题--所有实例化是B的实例,而不管方法解析顺序(__mro__)结果,如下:
class C(B):
b=2
tree=C()
#print tree.bAttributeError: ‘B‘ object has no attribute ‘b‘
"""
为了避免这样的限制,alex martelli提供了一个基于共享状态的替代实现,即borg
这个思路是,单例模式中真正重要的还是类存在的实例数量,而且它们在任何时候都将共享相同状态事实,所以
alex martelli引入了一个类,使用所有实例共享相同的__dict__,如下:
"""
class Borg(object):
_state={}
def __new__(cls, *args, **kwargs):
ob=super(Borg,cls).__new__(cls,*args,**kwargs)
ob.__dict__=cls._state
return ob
class B1(Borg):
a=1
a=B1()
b=B1()
b.a=3
print a.a
class B2(B1):
b=2
tree=B2()
print tree.b
print tree.a
tree.a=2
print a.a
"""
这解决了子类的问题,但是仍然依赖于子类代码的工作方式,如果__getattr__被重载,那么这个模式可能会被破坏。
虽然如此,单例不应该有多级别的继承,标记为单例的类已经是特殊类了
也就是说,该模式被许多开发人员视为处理应用程序唯一性问题的重要方法,如果需要一个单例,既然python模式也是一个单例,
那么为什么不使用带有函数的模块来代替呢
单例工厂是牗应用程序中唯一性的一个隐含方法,也可以不使用它,除非在一个使用java风格的框架,否则应该使用模块来代替类
"""
#结构型模式 有助于针对特定使用场景的代码结构模式
"""
它们决定代码的组织方式并且提供了开发人员和应用程序各部分交互的方法.
在python世界中,最著名的实现是zope component architecture(zope组件架构,简写为zca,请看:<http://wiki.zope.org/zope3/componentarchitectureoverview>)
它实现了大部分模式,并提供了处理这些模式的丰富工具集,zca并不只zope框架,还可用于诸如twisted之类的其他框架,还提供了界面和适配器的一个实现。
所以即使是不大的作品,也应该考虑用它,而不是从头开始重写这样的模式。
有很多从gof11原作中继承而来结构化模式
允许使用装饰器一个函数,但是不是在运行时,在未来版本中被扩展为类
如下:http://www.python.org/dev/peps/pep-3129
其他流行的模式是:
"""
#适配器:用来封闭一个类或者一个对象A,它可以工作在用于一个类或者对象B的上下文中
#当一些代码被用来处理一个指定的类,从另一个类给予它对象是很好的,这些对象提供代码所使用的方法和特性即可,这形成了python中的duck-typing思想的基础
#如果它走起来像鸭子,说起来也像鸭子,那么它就是鸭子
#当然,这假定代码没有调用instanceof以验证该实例是一个特定类
#我说它是一个鸭子,没有必要检查它的dna
#行为型模式 有助于对进程进行结构化的模式
"""
适配器基于这种思想并定义了一个封装机制,在这样的机制,封装了一个类或者对象,以便使其在不是为它提供上下文中工作,stringIO是个典型的例子
它改编了str类型使其可以像file类型一样使用,如图:
"""
from StringIO import StringIO
my_file=StringIO(u‘some content‘)
print my_file.read()
my_file.seek(0)
print my_file.read(1)
"""
再举个例子,dublincoreinfos类知道如何为指定的文档显示dublin core信息(请看http://dublincore.org),它读取几个字段
比如作者名或者标题并且打印,为了能够为一个文件显示dublin core,它必须和stringio一样改变,上面的图片给出了这个模式类-uml图,这个类提供了一个实例,并且提供了针对它的元数据访问,如下:
"""
from os.path import split,splitext
class Dublincoreinfos(object):
def __init__(self,filename):
self._filename=filename
def title(self):
return splitext(split(self._filename)[-1])[0]
def creator(self):
return ‘unknow‘#真实获取
def languages(self):
return (‘en‘,)
class dublincoreinfosinfo(object):
def summary(self,dc_ob):
print ‘title:%s‘%dc_ob.title()
print ‘creator:%s‘%dc_ob.creator()
print ‘languages :%s‘,‘,‘.join(dc_ob.languages())
adatep=Dublincoreinfos(‘example.txt‘)
info=dublincoreinfosinfo()
info.summary(adatep)
"""
除了允许替换之外,适配器模式不能改变开发人员的工作,改编一个对象使其工作于特定的上下文,设想对象是什么类无关紧要
重要的是这个类dublincoreinfosinfo()所期待的特性,这种行为由一个适配器来修复或者完成,所以代码只要以某种方式告知它与实现特定行为的对象兼容即可,而且是可以由接口(interfaces)来表示
"""
#1:接口
"""
是api的一个定义,它描述了一个类为所需要的行为必须实现的方法和特性的列表,这个描述不实现任何代码,只定义希望实现的该接口的类所用的明确契约(contract)之后,任何类都可以以其希望的方式实现一个或者多个对象。
虽然在python中,相比接定义更喜欢duck typing,但是有时候使用接口可能更好
这样做的好处是:类是低耦合的,这被认为是好的做法
许多开发人员要求将接口添加为python的核心功能,当前这些希望使用接口的人现在都被迫使用zope接口或者pyprotocols
以前,guido拒绝将接口添加到python中,因为它们不适合python动态的duck-typing特性,但是,接口系统在某些情况下证明了它们价值,所以python3000将引入一个被称为
option type annotations(可选类型符号)的特性,这个特性可以作为针对第三方接口库的语法
"""
"""
最近python 3000还添加了抽象基类(ABC)支持,以下是从pep中摘录的
<abc只是被添加到对象继承中的python类,它用来向外部检查程序传达该对象某些功能>
适配器对于使类和执行上下文保持耦合而言是完美的,但是,如果将适配当作编程思想,而不是作为在特定过程中对必须使用的
对象做一个快速修复,那么应该用接口.
"""