标签:方法 imp 就会 作用 调用 ali clinet crete 精灵
每一个设计模式系统的命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。这里面向对象划重点,意思是所有的设计模式都是针对面向对象的提出的。之前已经接触过的设计模式有单例模式。
接口,就是一个类,声明了若干方法,要求继承该接口的子类必须实现这些方法。
接口的作用:限制方法的名称及调用方法,隐藏了类的内部实现。
第一种写法:
实际只有指导的用处,并不能对子类进行约束:
class Interface(object):
def method(self, arg):
raise NotImplementedError
class RealizeInterface(Interface):
def method(self, arg):
print("Realize Interface %s" % arg)
上面代码中的Interface就是接口类,之后的RealizeInterface就是一个继承了该接口的子类。在子类里必须实现接口类里定义的方法。
问题:这里只有指导作用,没有约束的作用。只有在子类调用接口的方法的时候才会报错,而且本来也会报一个没有该方法的错。
第二种写法:
按这面的写法定义,就能起到约束的效果:
from abc import ABCMeta, abstractclassmethod
class Interface(metaclass=ABCMeta): # 这是一个接口类,并且无法实例化
@abstractclassmethod # 这个方法必须被子类实现
def method(self, arg):
pass
class RealizeInterface(Interface):
# def method(self, arg): # 比如我就是不实现接口的方法
# print("Realize Interface %s" % arg)
def hello(self, arg):
print("Hello %s" % arg)
RealizeInterface() # 实例化的时候就会报错
下面是报错信息:
TypeError: Can‘t instantiate abstract class RealizeInterface with abstract methods method
没有method这个抽象方法,就不能实例化RealizeInterface这个类。
开放封闭原则。代码要对扩展开放,对修改关闭。
所以,尽量要在不修改源码的情况的进行扩展。
所有引用基类的地方,必须透明的使用其子类的对象。
就是,我在写高层代码实现的时候,不用管子类。只需要去查看基类的方法就好了。所有父类有的方法,子类都可以出现。python里应该不用特别关注了,因为子类都是继承父类的,已经这么做好了。
高层模块不应该依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
高层模块,比如是一个实例,然后去实现某个具体的方法、功能。
底层模块,比如就是子类
抽象,比如就是上面的接口类,它是抽象的
也就是说,功能的实现、子类都应该照着接口类来写。所有的代码都是依赖抽象也就是接口类的。虽然高层模块是通过调用底层模块,也就是子类来实现的。但是两者不要有依赖关系。两者都是照着接口类的要求去写就好了。
针对实现编程,就是去看一下子类的内容,然后实现它。这是不对的,不应该依赖子类的方法,不同的子类可能用不同的方法来实现功能。
针对接口编程,把高层函数里需要调用的方法都写在接口里。子类的代码要照着接口去实现。高层代码就只需要去查看接口类。
使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些它不需要的接口。
先说反例:现在有一个动物接口类,类里要实现在陆地上奔跑、在水中游泳、在天空飞翔这些方法。现在定义一个子类,比如老虎。接口要求我们子类必须实现接口类的全部的方法。问题来了,老虎只有奔跑的方法,没有其他方法,但是要求所有方法都要实现。
根据接口隔离,就需要我们把上面的接口分开,比如陆栖动物、水栖动物、飞行生物这么3个接口类。老虎类只需要继承陆气动物这个接口类就好了。如果要一只青蛙,或者鸭子,那么可以多继承,继承两个甚至三个。
为什么要这么做,结合里氏替换原则。如果我拿到一个对象,我不用关心这是老虎还是鸭子,我直接看接口类,有跑、有游、有飞。所以我认为3个方法都可以用。现在这里形象的用动物来举例子,实际中你看到的就是一段或者一大段代码,难以判断它哪些方法可以有,哪些方法应该没有,参考的就是接口类里有什么方法。
多继承,根据这个原则,就要用到多继承了。但是这里只是继承接口类,这是应该要这么做的,但是如果是其他的类,还是要避免多继承的。这是一个组合复用原则
一个软件实体(如类、模块、函数)应当尽可能少的与其他实体发生相互作用。
就是2个字:解耦。
不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
这是第7个了。
组合复用原则也叫合成/聚合复用原则(CARP),就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。
这个原则的简短表述就是:要尽量使用组合,尽量不要使用继承。
组合就是将已有的对象纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能。
先看一下,总共有哪些设计模式。挑了其中的一部分讲了一下。
分为3个大类,每个里面再有具体的模式
在讲2种工厂模式之前,先学习一下简单工厂模式。
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
角色:
优点:
缺点:
平时我们是自己通过调用类来创建一个对象的。在简单工厂模式里,它把创建对象的过程也放到了工厂类里。用户调用工厂类的创建方法,提供参数,拿到返回的创建好的对象:
from abc import abstractclassmethod, ABCMeta
# 先来定义接口类
class Dialog(metaclass=ABCMeta):
@abstractclassmethod
def say_hi(self):
pass
# 用英语实现一个Dialog接口
class English(Dialog):
def say_hi(self):
print(‘Hi‘)
# 用中文实现一个Dialog接口
class Chinese(Dialog):
def say_hi(self):
print("你好")
# 通过工厂类里的创建方法来创建实例
class DialogFactory(object):
def create_dialog(self, language): # 提供不同的参数,返回不同的实例
if language == ‘English‘: # 这里会有很多的elif,也是这个模式的一个缺点
return English()
elif language == ‘Chinese‘:
return Chinese()
else:
raise NameError(language)
# 这里是高层模块的实现方法
f = DialogFactory() # 先实例化工厂类
d1 = f.create_dialog(‘English‘) # 通过调用工厂类的方法,获得一个产品实例
d2 = f.create_dialog(‘Chinese‘)
d1.say_hi()
d2.say_hi()
在上面代码的基础上,现在要再加一个功能,比如要用火星文。底层还是把这个算作是中文的一种,实现的时候给中文实现的类里通过加一个参数来控制。
# 新的中文类的实现,扩展了一个功能,用参数控制
class Chinese(Dialog):
def __init__(self, leetspeak=False):
self.leetspeak = leetspeak
def say_hi(self):
if self.leetspeak:
print("妳恏")
else:
print("你好")
# 上面添加了新产品,这里需要修改工厂类代码才能用
class DialogFactory(object):
def create_dialog(self, language):
if language == ‘English‘:
return English()
elif language == ‘Chinese‘:
return Chinese()
elif language == ‘Mars‘:
return Chinese(True)
else:
raise NameError(language)
# 高层的实现完全没有变化,原来的照样能用。新加的产品也像之前的产品一样使用
# 并且隐藏了底层的实现,看不出其实两个产品是同一个类是实现的,只是实例化的时候,通过参数来控制
f = DialogFactory()
d1 = f.create_dialog(‘English‘)
d2 = f.create_dialog(‘Chinese‘)
d1.say_hi()
d2.say_hi()
d3 = f.create_dialog(‘Mars‘)
d3.say_hi()
但是上面最后实现的时候,完全和其他方法一样,虽然在接口,其实是和中文实现是同一个类,只是参数不同,但是这些都隐藏了,最后实现的时候完全不用关心这些细节。
之前的已经实现的部分,不需要做任何修改,原来能用,扩展后依然能用。新扩展的内容的对用方法也和之前已经实现的内容完全一样(虽然底层的实现是不同的)。有点的第2条,客户端不用修改代码。
缺点的第一条,可能是这样的。上面的例子比较简单,只实现了一个方法。实际使用时,你的工厂类可能要实现很多方法,各种方法的逻辑都可能不同。违反单一职责原则。
缺点的第二条,在例子里扩展功能的时候已经很明显了,改了工厂类的代码。
在上面简单工厂模式的基础上来理解工厂方法模式。
内容:定义一个用处创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色:
工厂方法模式想不简单工厂模式,将每个具体产品都对应了一个具体工厂。
就是在简单工厂模式的基础上,把工厂类再抽象出来。现在不再把所有的产品都放到一个工厂里,而是先抽象一个工厂接口类,然后为每个产品定义一个具体的工厂类。
# 先抽象一个工厂类,就是工厂的接口类
class DialogFactory(object):
def create_dialog(self):
raise NotImplementedError
# 然后,对于每一种产品都单独建一个工厂
class EnglishDialogFactory(DialogFactory):
def create_dialog(self):
return English()
class ChineseDialogFactory(DialogFactory):
def create_dialog(self):
return Chinese()
class MarsDialogFactory(DialogFactory):
def create_dialog(self):
return Chinese(True)
f1 = EnglishDialogFactory()
f2 = ChineseDialogFactory()
d1 = f1.create_dialog()
d2 = f2.create_dialog()
d1.say_hi()
d2.say_hi()
f3 = MarsDialogFactory()
d3 = f3.create_dialog()
d3.say_hi()
试用场景:
优点:
缺点:每增加一个具体产品类,就必须增加一个相应的具体工厂类
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
角色:
例子:首先有一系列的产品,有水果:苹果、香蕉,可以做成派或者果汁。那就需要先有一种水果,然后选择做成什么食物。
一种水果、一种加工方法,称作一个产品系列
苹果和香蕉,称作一个产品簇
# 抽象产品,这个有多个抽象产品
class Fruit(metaclass=ABCMeta):
@abstractclassmethod
def get(self):
pass
class Food(metaclass=ABCMeta):
@abstractclassmethod
def make(self):
pass
# 具体产品
class Apple(Fruit):
def get(self):
return "获得一个苹果"
class Banana(Fruit):
def get(self):
return "获得一个香蕉"
class Pie(Food):
def make(self):
return "做了一个派"
class Juice(Food):
def make(self):
return "榨了一杯果汁"
# 抽象工厂,工厂接口类。
# 接口要求实现2个步骤,获取水果,做成食物
class Factory(metaclass=ABCMeta):
@abstractclassmethod
def get_fruit(self):
pass
@abstractclassmethod
def make_food(self):
pass
# 具体工厂,子类里要创建一系列对象并返回
# 实现接口的2个方法,更多工厂就不写了
class ApplePieFactory(Factory):
def get_fruit(self):
return Apple()
def make_food(self):
return Pie()
# 客户端的实现
class Food(object):
def __init__(self, fruit, food):
self.fruit = fruit
self.food = food
def make_food(self):
fruit = self.fruit.get()
food = self.food.make()
return "%s,%s" % (fruit, food)
# 把工厂类返回的产品实例传递给客户端的类
# 客户的类里对产品做各种实现
def get_product(factory):
fruit = factory.get_fruit()
food = factory.make_food()
return Food(fruit, food)
# 这里是高层代码的实现
# 上面定义了一大堆底层,到这里调用起来就确实是很方便的
f1 = get_product(ApplePieFactory())
print(f1.make_food())
相比工厂方法模式,抽象工厂模式中的每个具体的工厂都生产一套产品。
工厂方法模式的工厂类只调用一个产品。抽象工厂模式的例子中,工厂类要调用多个产品。
适用场景:
优点:
缺点:难以支撑性种类的抽象产品
比如上面的例子中是2个过程,如果要再加产品组合进来,必须可以选择堂食、外带。要按照这个设计模式的思路进行扩展的话,抽象工厂也就是接口类就需要加一个产品进去。基本上所有的底层都要改了。
这个不算工厂模式,但是和工厂模式非常相似。
内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
角色:
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
多类产品,每类产品有好几种,这是抽象工厂模式
多类产品,没类产品只有一种,这是建造者模式
一类产品,没类产品有好几种,这是工厂方法模式
例子:来捏个脸,最终要生成的就是一张脸。然后要捏出一张脸,需要多个产品类,比如眼睛、耳朵、鼻子、嘴巴这里就用那么多。
# 产品
class Face(object):
def __init__(self, eye=None, ear=None, nose=None, mouth=None):
self.eye = eye
self.ear = ear
self.nose = nose
self.mouth = mouth
def __str__(self):
return "%s, %s, %s, %s" % (self.eye, self.ear, self.nose, self.mouth)
# 建造者,相当于之前的工厂
class FaceBuilder(metaclass=ABCMeta):
@abstractclassmethod
def build_eye(self):
pass
@abstractclassmethod
def build_ear(self):
pass
@abstractclassmethod
def build_nose(self):
pass
@abstractclassmethod
def build_mouth(self):
pass
# 这个接口方法是的多出来的,目的就是把上面的多个产品组合成最终的一个大产品
@abstractclassmethod
def get_face(self):
pass
# 在这里组装
class GirlFaceBuilder(FaceBuilder):
def __init__(self):
self.face = Face()
def build_eye(self):
self.face.eye = "大眼睛"
def build_ear(self):
self.face.ear = "精灵耳朵"
def build_nose(self):
self.face.nose = "挺鼻梁"
def build_mouth(self):
self.face.mouth = "樱桃小嘴"
def get_face(self):
return self.face
# 指挥者,保证所有的产品都被调用了,保证各个产品的调用顺序
class FaceDirector(object):
def build_face(self, builder):
builder.build_eye()
builder.build_ear()
builder.build_nose()
builder.build_mouth()
return builder.get_face()
# 高端模块的调用
d1 = FaceDirector() # 创建一个指挥者
b1 = GirlFaceBuilder() # 创建一个建造者
f1 = d1.build_face(b1) # 调用指挥者的方法,把建造者作为参数传入
print(f1)
适用场景:
优点:
Builder隐藏了内部结构(工厂模式也有)。多了个Director,多隐藏了装配过程。
上面那么多的模式,掌握工厂方法模式就好了,其他的看不懂就算了。
其他模式比使用工厂方法模式更灵活,但是它们更加复杂。通常,设计以使用工厂方法模式开始,并且当设计者发现需要更大的灵活性时,设计便会向其他创建型模式演化。
依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式、创建者模式
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
角色:单例(Singleton)
适用场景:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
优点:
与单例模式功能相似的概念:全局变量、静态变量(方法)。既然3个概念的作用差不多,单例模式要比另外2个要好,所以需要用到上面的概念的时候,可以考虑用单例模式。
python中的单例模式
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
这里的做法是把单例模式的类做成一个基类,只要继承了这个类的子类就是单例模式的。之前用过单例,是直接在需要单例的类里定义一个new方法。两种方法都是可以的。
内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
角色:
两种实现方式:
这里的例子还是以上面简单工厂里的例子来扩展,现在有扩展了一个功能,但是没有继承我们的接口,或者是继承了别的接口,总之就是没有按照创建型模式规定的来:
# 再写一个实现,但是没有按照接口写,或者没有按照我们的接口写
class British(object):
def say_hello(self):
print(‘Hello‘)
假如这是一段很长很复杂的代码,本身没问题,就是没有写成我们要的样子。总之就是要用,但是不能改源码。
类适配器:
# 工厂类
class DialogFactory(object):
def create_dialog(self, language):
if language == ‘English‘:
return English()
elif language == ‘British‘:
return BritishDialog() # 类适配器的这一层已经和别的一样了
elif language == ‘Chinese‘:
return Chinese()
elif language == ‘Mars‘:
return Chinese(True)
else:
raise NameError
# 类适配器
class BritishDialog(Dialog, British):
def say_hi(self):
return self.say_hello()
使用类适配器的话,如果有好几个需要适配的类,我们就是对应写几个适配器。有一个类就要写一个适配器。
对象适配器:
# 工厂类
class DialogFactory(object):
def create_dialog(self, language):
if language == ‘English‘:
return English()
elif language == ‘British‘:
return BritishDialog(British()) # 对象适配器的这一层和别的都不一样
elif language == ‘Chinese‘:
return Chinese()
elif language == ‘Mars‘:
return Chinese(True)
else:
raise NameError
# 对象适配器
class BritishDialog(Dialog):
def __init__(self, dialog):
self.dialog = dialog
def say_hi(self):
return self.dialog.say_hello()
f = DialogFactory()
d4 = f.create_dialog(‘British‘)
d4.say_hi()
这种方法,无论写了几个非标准的sya_hello方法,都适配成了say_hi方法了。但是用对象适配器的话,实例化产品的方法就和别人不一样了,具体看工厂类里的返回实例的那行。
缺点就是实例化的方法和别的不一样,这里有工厂方法隐藏了,也就没什么问题。如果没有采用工厂模式,那么高层代码在写的时候就会和别的不一样。
适用场景:
内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
角色:
每一个组件可以和其他一个或多个组件进行组合,组合后成为一个新的组件。组合的组件也是一个组件,可以和别的组件继续组合下去。无论是你叶子组件还是复合组件。
下面的例子,先定义了一个抽象组件,然后实现了叶子组件(即基础图形)。然后通过基础图形,可以组合出各种复合图形。复合图形还可以再复合:
from abc import abstractclassmethod, ABCMeta
# 抽象组件,图形的接口类
class Line(metaclass=ABCMeta):
@abstractclassmethod
def draw(self): # 画出图形的接口
pass
@abstractclassmethod
def add(self, line): # 进行组合的接口
pass
def get_children(self):
pass
# 叶子组件,基础图形
class ShortLine(Line):
def __init__(self):
self.line = ‘*** ***‘
def draw(self):
print(self.line)
def add(self, line): # 基础图形,不能添加
raise TypeError
def get_children(self): # 不能添加,自然也不会有孩子
raise TypeError
class LongLine(Line): # 还是一个基础图形
def __init__(self):
self.line = ‘*******‘
def draw(self):
print(self.line)
def add(self, line):
raise TypeError
def get_children(self):
raise TypeError
# 复合组件,各种基础图形或者复合图形组合后的图形
class Pic(Line):
def __init__(self):
self.children = [] # 列表里存了复合了哪些图形
def draw(self):
for i in self.children:
i.draw()
def add(self, line): # 可以组合各种图形(基础图形或组合图形)
self.children.append(line)
def get_children(self):
return self.children
# 先把基础图形画出来看看
short_line = ShortLine()
lang_line = LongLine()
print("基础图形")
short_line.draw()
lang_line.draw()
# 画复合图形
qian = Pic()
qian.add(lang_line)
qian.add(lang_line)
qian.add(lang_line)
print("天乾")
qian.draw()
kan = Pic()
kan.add(short_line)
kan.add(lang_line)
kan.add(short_line)
print("水坎")
kan.draw()
# 用组合后的图形继续组合
song = Pic()
song.add(qian)
song.add(kan)
print("天水讼,把2个图形组合起来")
song.draw()
应用狭窄,只能用到树形结构上。目的简单,用简单的对象组合生成复杂的对象,并且组合后行为上还能保持一致,。
适用场景:
优点:
缺点:很难限制组合中的组件
内容:为其他对象提供一种代理以控制对这个对象的访问。
角色:
适用场景:
优点:
下面是代理模式的例子:
from abc import ABCMeta, abstractmethod
class Subject(metaclass=ABCMeta):
@abstractmethod
def get_content(self):
pass
class RealSubject(Subject):
def __init__(self, filename):
print("读取文件内容:%s" % filename)
f = open(filename)
self.content = f.read()
f.close()
def get_content(self):
return self.content
# 这个不是远程代理,远程代理没举例
# 下面是个没任何作用的代理
# 只是给上面的实体类封了一层壳,功能和收么的类完全一样
# 不过好歹是实现了代理,不直接把对象暴露出来
class ProxyA(Subject):
def __init__(self, filename):
self.subj = RealSubject(filename)
# 调用代理的一个方法,实际就是调用self.subj的对应的方法
# 这里写死了,应该可以做个反射,全部指过去
def get_content(self):
return self.subj.get_content()
# 虚代理
# 这个代理最初只保存一下文件名,但是不实例化
# 只有调用了get_content方法时,才会检查是否有实例,如果没有才创建对象
class ProxyB(Subject):
def __init__(self, filename):
self.filename = filename
self.subj = None
def get_content(self):
if not self.subj:
self.subj = RealSubject(self.filename)
return self.subj.get_content()
# 保护代理
# 这个类实现的不是很好
class ProxyC(Subject):
def __init__(self, filename):
self.subj = RealSubject(filename)
def get_content(self): # 假设这个就是权限受限时提供的文件内容
return "??????"
通过代理,可以给原来的类添加或者修改功能,但是又不用修改原来的代码。添加和修改功能,例子里貌似没体现,不过只要去代理里面改代码就能实现了。代理里拿到了实体的对象后,可以直接在代理里根据需要修改对象。
内容:是多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
角色:
举例:
请假的例子:
from abc import ABCMeta, abstractmethod
class Handler(metaclass=ABCMeta):
@abstractmethod
def handle_leave(self, day):
pass
class Supervisor(Handler):
def __init__(self):
self.successor = DepartmentManagerHandler()
def handle_leave(self, day):
if day < 3:
print("主管批准%d天假期" % day)
else:
print("主管无权准假")
self.successor.handle_leave(day)
class DepartmentManagerHandler(Handler):
def __init__(self):
self.successor = GeneralManagerHandler()
def handle_leave(self, day):
if day < 7:
print("部门经理批准%s天假期" % day)
else:
print("部门经理无权准假")
self.successor.handle_leave(day)
class GeneralManagerHandler(Handler):
def handle_leave(self, day):
if day < 15:
print("总经理批准%d天假期" % day)
else:
print("驳回")
day = 10
h = Supervisor()
h.handle_leave(day)
Javascript的事件浮升机制:
from abc import ABCMeta, abstractmethod
class Handler(metaclass=ABCMeta):
@abstractmethod
def add_event(self, func):
"""增加事件的方法"""
pass
@abstractmethod
def handle(self):
"""处理事件的方法"""
pass
class BodyHandler(Handler):
def __init__(self):
self.func = None
def add_event(self, func):
self.func = func
def handle(self):
"""最顶端的handle方法单独写"""
if self.func:
return self.func()
else:
print("没有事件处理")
class ElementHandler(Handler):
def __init__(self, successor):
self.func = None
self.successor = successor
def add_event(self, func):
self.func = func
def handle(self):
"""其他handle方法都是通用的,关键是下面的客户端要写好对应关系"""
if self.func:
return self.func()
else:
return self.successor.handle()
# 客户端
body = {‘type‘: ‘body‘, ‘name‘: ‘body‘, ‘father‘: None, ‘children‘: []}
div = {‘type‘: ‘div‘, ‘name‘: ‘div‘, ‘children‘: [], ‘father‘: body}
a = {‘type‘: ‘a‘, ‘name‘: ‘a‘, ‘children‘: [], ‘father‘: div}
body[‘children‘].append(div)
div[‘children‘].append(a)
body[‘event_handler‘] = BodyHandler()
div[‘event_handler‘] = ElementHandler(div[‘father‘][‘event_handler‘])
a[‘event_handler‘] = ElementHandler(a[‘father‘][‘event_handler‘])
def attach_event(element, func):
element[‘event_handler‘].add_event(func)
# 高端模块调用
# 这里相当于写了事件处理函数
def func_body():
print("这是给body的函数")
def func_div():
print("这是给div的函数")
def func_a():
print("这是给a的函数")
# 这里相当于把事件处理函数绑定到标签上
attach_event(body, func_body)
attach_event(div, func_div)
# attach_event(a, func_a)
a[‘event_handler‘].handle()
适用场景:
优点:降低耦合度。一个对象无需知道是其他哪一个对象处理其请求
缺点:请求不保证被接收。链的末端没有处理或链配置错误
内容:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
实现方法:__iter__
、__next__
内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,?所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式
角色:
适用场景:
优点:
缺点:多个观察者之间互不知道对方存在,因此一个观察者对主题的修改可能造成错误的更新。
这个模式主要的用途就是发布-订阅。
内容:定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。本模式使得算法可独立于使用它的客户而变化。
不同的算法,在策略模式里也可以理解为不同的策略。
角色:
下面的例子,先定义了一个抽象策略,就是排序。然后写了2个排序算法,作为2个具体策略。然后看下上文类,在创建对象的时候,可以传入一个策略。之后可以通过体格的set方法修改策略。类里还提供了一个do方法,使用策略进行排序:
from abc import ABCMeta, abstractmethod
import random
class Sort(metaclass=ABCMeta):
@abstractmethod
def sort(self, data):
pass
class QuickSort(Sort):
@staticmethod
def quick_sort(li):
"""这个是之前讲排序的时候的快排函数"""
def _quick_sort(li, left, right):
if left < right:
mid = partition(li, left, right)
# print(li)
_quick_sort(li, left, mid - 1)
_quick_sort(li, mid + 1, right)
return li
def partition(li, left, right):
tmp = li[left]
while left < right:
while left < right and li[right] >= tmp:
right -= 1
li[left] = li[right]
while left < right and li[left] <= tmp:
left += 1
li[right] = li[left]
# 到这里left和right是一样的了,所以用left少个字母
li[left] = tmp
return left
left = 0
right = len(li) - 1
return _quick_sort(li, left, right)
def sort(self, data):
print("使用快速排序算法进行排序")
return self.quick_sort(data)
class PythonSort(Sort):
def sort(self, data):
data.sort()
print("使用Python内置方法进行排序")
return data
class Context(object):
def __init__(self, data, strategy=None):
self.data = data
self.data_copy = None
self.strategy = strategy # 实例化的时候可以把策略传进来
def set_strategy(self, strategy):
"""提供了一个方法,可以修改策略"""
self.strategy = strategy
def do_strategy(self):
if self.strategy:
self.data_copy = self.data.copy()
print("排序前:", self.data_copy)
self.strategy.sort(self.data_copy)
else:
raise TypeError
# 高端模块的调用
li = list(range(10))
random.shuffle(li) # 洗牌
context = Context(li, PythonSort())
context.do_strategy()
print("排序后:", context.data_copy)
context.set_strategy(QuickSort()) # 设置换个策略
context.do_strategy() # 再在做一个排序
print("排序后:", context.data_copy)
上面的例子实现了方便的在多种策略之间进行切换。
适用场景:
优点:
缺点:
内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:
适用场景:
举例,比如处理文件、数据库、Socket,都是3步:打开、处理、关闭。在抽象类里就定义好这3个接口,另外再写一个实现的类process,所有的子类用的都是process的实现过程。流程在父类的process里定义,子类只负责实现各自不同的接口:
rom abc import abstractclassmethod, ABCMeta
class IOHandler(metaclass=ABCMeta):
@abstractclassmethod
def open(self, name):
pass
@abstractclassmethod
def deal(self, change):
pass
@abstractclassmethod
def close(self):
pass
def process(self, name, change):
self.open(name)
self.deal(change)
self.close()
class FileHandler(IOHandler):
def open(self, name):
self.file = open(name, ‘a‘)
def deal(self, change):
self.file.writelines([change])
def close(self):
self.file.close()
# 高端模块的实现
f = FileHandler()
f.process(‘test.txt‘, ‘TEST‘)
标签:方法 imp 就会 作用 调用 ali clinet crete 精灵
原文地址:http://blog.51cto.com/steed/2155310