1.设计模式简介
1.简介
在特定情形下实现方法的模板,不会绑定任何语言。
2.常用的设计模式
创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式.
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式.
行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。
2.创建型模型
1.单例模式
1.概念
是什么?:一个类只能产生一个实例, 并提供一个访问它的全局访问点。
为什么?:全局需要唯一的类的实例对象。
适用场景:当类只能产生一个实例,并提供一个全局访问接口;当该类通过子类扩展时,子类无需更改代码也是单例模式。
2.代码
class Person(object):
_is_init = False
# 实现单例模式
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
# cls._instance = super(Person, cls).__new__(cls, *args, **kwargs) # python 2.7
cls._instance = super(Person, cls).__new__(cls) # python 3.5
return cls._instance
def __init__(self, name, age):
if not self._is_init:
self.name = name
self.age = age
self._is_init = True
def __str__(self):
return self.name
if __name__ == '__main__':
p1 = Person('xiaohua', 18)
p2 = Person('xiaowang', 19)
# p1和p2同一地址
print(id(p1), id(p2))
# 只初始化了第一次
print(p1, p2)
2.工厂模式
1.概念
是什么?:就是将创建不同类型实例的代码抽离出来,封装成一个工厂类(实际上用一个函数更加直接)。
为什么?:将类的实例化和使用解耦,隐藏了实例化过程的复杂度,降低了维护的复杂性。
适用场景:当不知道实例化那个类的时候;当一个类希望由它的子类来指定它所创建的对象时候。
2.实现
class ChinaGetter:
def __init__(self):
self.trans = dict(dog="小狗", cat="小猫")
def get(self, msg_id):
try:
return self.trans[msg_id]
except KeyError:
return str(msg_id)
class EnglishGetter:
def get(self, msg_id):
return str(msg_id)
class Factory:
@staticmethod
def get_localizer(language="English"):
languages = dict(English=EnglishGetter, China=ChinaGetter)
return languages[language]()
if __name__ == '__main__':
e, c = Factory.get_localizer("English"), Factory.get_localizer("China")
for msg_id in "dog parrot cat bear".split():
print(e.get(msg_id), c.get(msg_id))
3.抽象工厂模式
1.概念
是什么?:就是对工厂模式的工厂进行进一步的抽象化。
从工厂模式可以指定:根据用户输入的不同,调用相同的工厂,将会输出不同的结果。
那么抽象工厂模式呢?根据用户输入的不同,调用相同的接口,去调用不同的工厂进行不同的生产,得出不同的输出结果。(个人理解)
为什么?
抽象工厂模式的优点:
1、工厂模式巨有非常好的封装性,代码结构清晰;在抽象工厂模式中,其结构还可以随着需要进行更深或者更浅的抽象层级调整,非常灵活。
2、屏蔽产品类,使产品的被使用业务场景和产品的功能细节可以分而开发进行,是比较典型的解耦框架。
3.当系统实例要求比较灵活和可扩展时候,可以考虑工厂模式和抽象工厂模式。
缺点:
1、工厂模式相对于直接生成实例过程要复杂一些,所以,在小项目中,可以不使用工厂模式。
2、抽象工厂模式中,产品类的扩展比较麻烦。毕竟,每一个工厂对应每一类产品,产品扩展,就意味着相应的抽象工厂也要扩展。
2.代码
from abc import ABCMeta, abstractmethod
# 创建一个造轮子的抽象类工厂
class AbstractFactory(metaclass=ABCMeta):
@abstractmethod
def create_wheel(self, abs_wheels):
pass
# 创建使用轮子的抽象类工厂
class AbstractWheel(metaclass=ABCMeta):
@abstractmethod
def use_wheel(self, factory_name):
pass
# 创建一个摩拜自行车--->使用轮子的抽象类工厂
class Mobai(AbstractWheel):
def __init__(self):
self.name = "摩拜单车"
def use_wheel(self, factory_name):
print("大家好!我是来自于{}的{}".format(factory_name, self.name))
# 创建一个OFO自行车--->使用轮子的抽象类工厂
class Ofo(AbstractWheel):
def __init__(self):
self.name = "Ofo"
def use_wheel(self, factory_name):
print("大家好!我是来自于{}的{}".format(factory_name, self.name))
# 创建bike类--->造轮子的抽象类工厂
class Bike(AbstractFactory):
def __init__(self, factory_name):
self.name = factory_name
def create_wheel(self, abs_wheels):
self.bike = abs_wheels()
self.bike.use_wheel(self.name)
if __name__ == '__main__':
bike = Bike("亚麻跌工厂")
# 这个工厂不仅造摩拜的轮子,还可以造Ofo的轮子
bike.create_wheel(Mobai)
bike.create_wheel(Ofo)
4.建造者模型
1.概念
是什么?:又称生成器模式, 是一种对象构建模式,是将复杂对象的建造过程抽象出来,使不同的实现方法可以构造不同的表现(属性)的对象。将一个复杂的对象的构建与它的表示分离。
为什么?主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
2.代码
# 具体产品对象
class Menu:
Menu_A = []
Menu_B = []
def set_MenuA(self, item):
self.Menu_A.append(item)
def set_MenuB(self, item):
self.Menu_B.append(item)
def get_MenuA(self):
return self.Menu_A
def get_MenuB(self):
return self.Menu_B
# Builder(抽象建造者)
# 创建一个Product对象的各个部件指定的抽象接口。
class Product:
product = Menu()
def build_hanbao(self):
pass
def build_jiroujuan(self):
pass
def build_kele(self):
pass
def build_shutiao(self):
pass
# ConcreteBuilder(具体建造者)
# 实现抽象接口,构建和装配各个部件。
# 套餐A
class product_A(Product):
type = "A"
def build_hanbao(self):
self.hanbao = "汉堡"
self.product.set_MenuA(self.hanbao)
def build_kele(self):
self.kele = "可乐"
self.product.set_MenuA(self.kele)
def getType(self):
return type
# 套餐B
class product_B(Product):
type = "B"
def build_shutiao(self):
self.shutiao = "薯条"
self.product.set_MenuB(self.shutiao)
def build_jiroujuan(self):
self.jiroujuan = "鸡肉卷"
self.product.set_MenuB(self.jiroujuan)
def build_kele(self):
self.kele = "可乐"
self.product.set_MenuB(self.kele)
def getType(self):
return type
# Director(指挥者)
class Make:
def __init__(self):
self.builder = None
def build_product(self, builder):
self.builder = builder
print(builder.type)
if builder.type == "A":
[step() for step in (builder.build_hanbao,
builder.build_kele)]
if builder.type == "B":
[step() for step in (builder.build_shutiao,
builder.build_jiroujuan,
builder.build_kele)]
# 不同类型选择
def validate_style(builders):
global valid_input
try:
print('套餐A:汉堡、可乐' + '\n' + '套装B:薯条、鸡肉卷、可乐')
product_style = input('请输入您的选择:')
builder = builders[product_style]()
valid_input = True
except KeyError as err:
print('Sorry, 没有这个套餐,请重新选择。')
return (False, None, None)
return (True, builder, product_style)
# 主函数
if __name__ == "__main__":
# 简单工厂模式
builders = dict(A=product_A, B=product_B)
valid_input = False
while not valid_input:
valid_input, builder, product_style = validate_style(builders)
# 创建流程
Make().build_product(builder)
# 根据配方选择结果
if product_style == "A":
print(builder.product.get_MenuA())
else:
print(builder.product.get_MenuB())
5.原型模式
1.概念
是什么?:原型模式关注的是大量相同对象或相似对象的创建问题,意图在于通过复制一个已经存在的实例来获得一个新的实例,以避免重复创建此类实例带来的开销。被复制的实例就是这个“原型”,这个原型是可定制的。
为什么?:原型模式可以避免重复创建此类实例的开销。
2.代码
from copy import copy, deepcopy
class simpleLayer:
"""
设计一个图层对象,用background表示背景的RGBA,简单用content表示内容,除了直接绘画,还可以设置透明度。
"""
background=[0,0,0,0]
content="blank"
def getContent(self):
return self.content
def getBackground(self):
return self.background
def paint(self,painting):
self.content=painting
def setParent(self,p):
self.background[3]=p
def fillBackground(self,back):
self.background=back
def clone(self):
return copy(self)
def deep_clone(self):
return deepcopy(self)
if __name__=="__main__":
dog_layer=simpleLayer()
dog_layer.paint("Dog")
dog_layer.fillBackground([0,0,255,0])
print("Background:",dog_layer.getBackground())
print("Painting:",dog_layer.getContent())
another_dog_layer=dog_layer.clone()
# 通过复制(clone)这个动作实现画一只同样的狗
print("Background:", another_dog_layer.getBackground())
print("Painting:", another_dog_layer.getContent())
3.结构型模式
1.适配器模式
1.概念
是什么?:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端
为什么?:适配接口
2.代码
class Dog:
def __init__(self):
self.name = "caicai"
def call(self):
print("旺旺旺")
class Cat:
def __init__(self):
self.name = "xiaomaomi"
def smile(self):
print("爱笑的小猫咪 喵喵")
class Adapter:
def __init__(self, obj):
self.obj = obj
# 创建一个适配狗的适配器
def smile(self):
self.obj.call()
if __name__ == '__main__':
dog = Dog()
cat = Cat()
list_animals = []
list_animals.extend([Adapter(dog), cat])
for i in list_animals:
i.smile()
2.桥接模式
1.概念
是什么?: 将抽象部分与它的实现部分分离,使它们都可以独立地变化。
为什么?:实现抽象部分和实现部分的解耦
2.代码
# 抽象类:人
class Human():
skill = None
def set_skill(self, skill):
self.skill = skill
def perform_skill(self):
pass
# 具体抽象类:码农
class Cs(Human):
def perform_skill(self): # 重写基类中的技能
print('我是码农,给我力量吧!')
self.skill.perform_skill()
# 具体抽象类:老师
class Teacher(Human):
def perform_skill(self): # 重写基类中的技能
print('我是教师,给我力量吧!')
self.skill.perform_skill()
# 功能类:技能
class Skill():
def perform_skill(self):
pass
# 具体功能类:编程
class S_code(Skill):
def perform_skill(self):
print('我拥有编程技能!')
# 具体功能类:上课
class S_teach(Skill):
def perform_skill(self):
print('我拥有教书技能!')
# 测试
if __name__ == '__main__':
s1 = S_code() # 编程技能
s2 = S_teach() # 教书技能
h1 = Cs() # 程序员
h1.set_skill(s1) # 赋予程序员编程技能
h1.perform_skill() # 演示这个技能
h1.set_skill(s2) # 赋予程序员教书技能
h1.perform_skill() # 演示教书技能
h2 = Teacher() # 教师
h2.set_skill(s1) # 赋予教师编程能力
h2.perform_skill() # 演示这个技能
h2.set_skill(s2) # 赋予教师教书技能
h2.perform_skill() # 演示教书技能
3.装饰模式
1.概念
是什么?:可以不改变一个对象功能的基础上增加额外的新行为
为什么?:扩展功能
2.代码
class Beverage():
name = ""
price = 0.0
type = "BEVERAGE"
def getPrice(self):
return self.price
def setPrice(self, price):
self.price = price
def getName(self):
return self.name
class coke(Beverage):
def __init__(self):
self.name = "coke"
self.price = 4.0
class milk(Beverage):
def __init__(self):
self.name = "milk"
self.price = 5.0
#除了基本配置,快餐店卖可乐时,可以选择加冰,如果加冰的话,要在原价上加0.3元;
# 卖牛奶时,可以选择加糖,如果加糖的话,要原价上加0.5元。怎么解决这样的问题?
# 可以选择装饰器模式来解决这一类的问题。首先,定义装饰器类:
class drinkDecorator():
def getName(self):
pass
def getPrice(self):
pass
class iceDecorator(drinkDecorator):
def __init__(self, beverage):
self.beverage = beverage
def getName(self):
return self.beverage.getName() + " +ice"
def getPrice(self):
return self.beverage.getPrice() + 0.3
class sugarDecorator(drinkDecorator):
def __init__(self, beverage):
self.beverage = beverage
def getName(self):
return self.beverage.getName() + " +sugar"
def getPrice(self):
return self.beverage.getPrice() + 0.5
#构建好装饰器后,在具体的业务场景中,就可以与饮料类进行关联。以可乐+冰为例,示例业务场景如下:
if __name__=="__main__":
coke_cola=coke()
print("Name:%s"%coke_cola.getName())
print("Price:%s"%coke_cola.getPrice())
ice_coke=iceDecorator(coke_cola)
print("Name:%s" % ice_coke.getName())
print("Price:%s" % ice_coke.getPrice())
4.组合模式
1.概念
是什么?将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性。
为什么?表示对象的部分-整体层次感觉。
2.代码
class Component:
def __init__(self, strName):
self.m_strName = strName
def Add(self, com):
pass
def Display(self, nDepth):
pass
class Leaf(Component):
def Add(self, com):
print("leaf cant add")
def Display(self, nDepth):
str_temp = "-" * nDepth
str_temp = str_temp + self.m_strName
print(str_temp)
class Composite(Component):
def __init__(self, strName):
self.m_strName = strName
self.c = []
def Add(self, com):
self.c.append(com)
def Display(self, nDepth):
str_temp = "-" * nDepth
str_temp = str_temp + self.m_strName
print(str_temp)
for com in self.c:
com.Display(nDepth+2)
if __name__ == '__main__':
p = Composite("wang")
p.Add(Leaf("Lee"))
p.Add(Leaf("Zhao"))
p1 = Composite("wu")
p1.Add(Leaf("wu"))
p.Add(p1)
p.Display(1)
5.外观模式
1.概念
是什么?: 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
为什么?:当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade 可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade 将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。
2.代码
import time
SLEEP_TIME = 0.5
class Tc1:
def run(self):
print("****in test 1 *****")
time.sleep(SLEEP_TIME)
print("****setting up*****")
time.sleep(SLEEP_TIME)
print("****running test*****")
time.sleep(SLEEP_TIME)
print("****tearing down*****")
time.sleep(SLEEP_TIME)
print("****finish*****")
class Tc2:
def run(self):
print("****in test 2 *****")
time.sleep(SLEEP_TIME)
print("****setting up*****")
time.sleep(SLEEP_TIME)
print("****running test*****")
time.sleep(SLEEP_TIME)
print("****tearing down*****")
time.sleep(SLEEP_TIME)
print("****finish*****")
class TestRunner:
def __init__(self):
self.tc1 = Tc1()
self.tc2 = Tc2()
self.tests = [i for i in (self.tc1, self.tc2)]
def runAll(self):
[i.run() for i in self.tests]
if __name__ == '__main__':
test_runner = TestRunner()
test_runner.runAll()
6.享元模式
1.概念
是什么?运用共享技术有效地支持大量细粒度的对象。
为什么?一个应用程序使用了大量的对象。完全由于使用大量的对象,造成很大的存储开销。对象的大多数状态都可变为外部状态。如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。 应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
2.代码
# 代码1
import weakref
class Card(object):
_CardPool = weakref.WeakValueDictionary()
def __new__(cls, value, suit):
obj = Card._CardPool.get(value + suit, None)
if not obj:
obj = object.__new__(cls)
Card._CardPool[value + suit] = obj
obj.value, obj.suit = value, suit
return obj
def __repr__(self):
return "<Card:%s%s>" % (self.value, self.suit)
if __name__ == '__main__':
c1 = Card("9", "h")
c2 = Card("9", "h")
print(c1, c2)
print(c1 == c2)
print(id(c1), id(c2))
# 代码2:
"""
大话设计模式
设计模式——享元模式
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象
对一个类进行的实例,只在第一次使用时建立,其他时候是用同一个实例,减少内存的开销
"""
# 抽象网站类
class Website(object):
def use(self):
pass
# 具体网站类
class ConcreteWebsite(Website):
def __init__(self, name):
self.name = name
def use(self):
print("网站分类", self.name)
# 不共享的网站类
class UnshareConcreteWebsite(Website):
def __init__(self, name):
self.name = name
def use(self):
print("不共享网站分类", self.name)
# 网站工厂
class WebsiteFactory(object):
def __init__(self):
self.hashtable = dict()
# 获取网站类 如果存在直接返回,如果不存在建好之后返回
def get_website(self, key):
if not key in self.hashtable:
self.hashtable[key] = ConcreteWebsite(key)
return self.hashtable[key]
# 网站实例的个数
def get_website_count(self):
return len(self.hashtable.keys())
if __name__ == "__main__":
factory = WebsiteFactory()
f1 = factory.get_website("blog")
f2 = factory.get_website("blog")
f3 = factory.get_website("blog")
f4 = factory.get_website("website")
f5 = factory.get_website("website")
f6 = factory.get_website("website")
f7 = UnshareConcreteWebsite("test")
f1.use()
f2.use()
f3.use()
f4.use()
f5.use()
f6.use()
f7.use()
7.代理模式
1.概念
是什么?:为其他对象提供一种代理以控制对这个对象的访问
为什么?:远程代理,虚代理,保护代理,智能指引。
2.代码
import time
class SalesManager:
def work(self):
print("Sales Manager working...")
def talk(self):
print("Sales Manager ready to talk")
class Proxy:
def __init__(self):
self.busy= 'No'
self.sales= None
def work(self):
print("Proxy checking for Sales Manager availability")
if self.busy =='No':
self.sales= SalesManager()
time.sleep(2)
self.sales.talk()
else:
time.sleep(2)
print("Sales Manager is busy")
if __name__ =='__main__':
p= Proxy()
p.work()
p.busy= 'Yes'
p.work()
4.行为型模式
1.模板方法模式
1.概念
是什么?:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
为什么?:模板方法模式是一种基于继承的代码复用技术 ,将一些复杂流程的实现步骤封装在一系列基本方法中 ,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果
2.代码
class StockQueryDevice():
stock_code="0"
stock_price=0.0
def login(self,usr,pwd):
pass
def setCode(self,code):
self.stock_code=code
def queryPrice(self):
pass
def showPrice(self):
pass
def operateQuery(self, usr, pwd, code):
if not self.login(usr, pwd):
return False
self.setCode(code)
self.queryPrice()
self.showPrice()
return True
class WebAStockQueryDevice(StockQueryDevice):
def login(self,usr,pwd):
if usr=="myStockA" and pwd=="myPwdA":
print("Web A:Login OK... user:%s pwd:%s"%(usr,pwd))
return True
else:
print("Web A:Login ERROR... user:%s pwd:%s"%(usr,pwd))
return False
def queryPrice(self):
print("Web A Querying...code:%s "%self.stock_code)
self.stock_price=20.00
def showPrice(self):
print("Web A Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price))
if __name__=="__main__":
web_a_query_dev=WebAStockQueryDevice()
web_a_query_dev.operateQuery("myStockA","myPwdA","12345")
2.命令模式
1.概念
是什么?:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
为什么?:抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(callback)函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。Command模式是回调机制的一个面向对象的替代品。在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。支持取消操作。Command的Excute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消”和“重做”。支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务( transaction)的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。
2.代码
import os
class MoveFileCommand(object):
def __init__(self, src, dest):
self.src= src
self.dest= dest
def execute(self):
self()
def __call__(self):
print('renaming {} to {}'.format(self.src,self.dest))
os.rename(self.src,self.dest)
def undo(self):
print('renaming {} to {}'.format(self.dest,self.src))
os.rename(self.dest,self.src)
if __name__ =="__main__":
command_stack= []
# commands are just pushed into the command stack
command_stack.append(MoveFileCommand('foo.txt','bar.txt'))
command_stack.append(MoveFileCommand('bar.txt','baz.txt'))
# they can be executed later on
for cmd in command_stack:
cmd.execute()
# and can also be undone at will
for cmd in reversed(command_stack):
cmd.undo()
3.迭代器模式
1.概念
是什么?:提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示
为什么?:访问一个聚合对象的内容而无需暴露它的内部表示,支持对聚合对象的多种遍历。,为遍历不同的聚合结构提供一个统一的接口(即支持多态迭代)。
2.代码
def count_to(count):
"""Counts by word numbers, up to a maximum of five"""
numbers = ["one", "two", "three", "four", "five"]
# enumerate() returns a tuple containing a count (from start which
# defaults to 0) and the values obtained from iterating over sequence
for pos, number in zip(range(count), numbers):
yield number
if __name__ == '__main__':
# Test the generator
count_to_two = lambda: count_to(2)
count_to_five = lambda: count_to(5)
print('Counting to two...')
for number in count_to_two():
print(number)
print("*" * 10)
print('Counting to five...')
for number in count_to_five():
print(number)
4.观察者模式
1.概念
是什么?:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
为什么?:当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
2.代码
class Subject(object):
def __init__(self):
self._observers= []
def attach(self, observer):
if not observer in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self, modifier=None):
for observer in self._observers:
if modifier !=observer:
observer.update(self)
# Example usage
class Data(Subject):
def __init__(self, name=''):
Subject.__init__(self)
self.name= name
self._data= 0
@property
def data(self):
return self._data
@data.setter
def data(self, value):
self._data= value
self.notify()
class HexViewer:
def update(self, subject):
print('HexViewer: Subject %s has data 0x%x'%
(subject.name, subject.data))
class DecimalViewer:
def update(self, subject):
print('DecimalViewer: Subject %s has data %d'%
(subject.name, subject.data))
# Example usage...
def main():
data1= Data('Data 1')
data2= Data('Data 2')
view1= DecimalViewer()
view2= HexViewer()
data1.attach(view1)
data1.attach(view2)
data2.attach(view2)
data2.attach(view1)
print("Setting Data 1 = 10")
data1.data= 10
print("Setting Data 2 = 15")
data2.data= 15
print("Setting Data 1 = 3")
data1.data= 3
print("Setting Data 2 = 5")
data2.data= 5
print("Detach HexViewer from data1 and data2.")
data1.detach(view2)
data2.detach(view2)
print("Setting Data 1 = 10")
data1.data= 10
print("Setting Data 2 = 15")
data2.data= 15
if __name__ =='__main__':
main()
5.中介者模式
1.概念
是什么?:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
为什么?:一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。想定制一个分布在多个类中的行为,而又不想生成太多的子类。
2.代码
import time
class TC:
def __init__(self):
self._tm= tm
self._bProblem= 0
def setup(self):
print("Setting up the Test")
time.sleep(1)
self._tm.prepareReporting()
def execute(self):
if not self._bProblem:
print("Executing the test")
time.sleep(1)
else:
print("Problem in setup. Test not executed.")
def tearDown(self):
if not self._bProblem:
print("Tearing down")
time.sleep(1)
self._tm.publishReport()
else:
print("Test not executed. No tear down required.")
def setTM(self, TM):
self._tm= tm
def setProblem(self, value):
self._bProblem= value
class Reporter:
def __init__(self):
self._tm= None
def prepare(self):
print("Reporter Class is preparing to report the results")
time.sleep(1)
def report(self):
print("Reporting the results of Test")
time.sleep(1)
def setTM(self, TM):
self._tm= tm
class DB:
def __init__(self):
self._tm= None
def insert(self):
print("Inserting the execution begin status in the Database")
time.sleep(1)
#Following code is to simulate a communication from DB to TC
import random
if random.randrange(1,4) ==3:
return -1
def update(self):
print("Updating the test results in Database")
time.sleep(1)
def setTM(self, TM):
self._tm= tm
class TestManager:
def __init__(self):
self._reporter= None
self._db= None
self._tc= None
def prepareReporting(self):
rvalue= self._db.insert()
if rvalue ==-1:
self._tc.setProblem(1)
self._reporter.prepare()
def setReporter(self, reporter):
self._reporter= reporter
def setDB(self, db):
self._db= db
def publishReport(self):
self._db.update()
rvalue= self._reporter.report()
def setTC(self, tc):
self._tc= tc
if __name__ =='__main__':
reporter= Reporter()
db= DB()
tm= TestManager()
tm.setReporter(reporter)
tm.setDB(db)
reporter.setTM(tm)
db.setTM(tm)
# For simplification we are looping on the same test.
# Practically, it could be about various unique test classes and their
# objects
while(True):
tc= TC()
tc.setTM(tm)
tm.setTC(tc)
tc.setup()
tc.execute()
tc.tearDown()
6.备忘录模式
1.概念
是什么?:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
为什么?:必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
2.代码
import copy
def Memento(obj, deep=False):
state= (copy.copy, copy.deepcopy)[bool(deep)](obj.__dict__)
def Restore():
obj.__dict__.clear()
obj.__dict__.update(state)
return Restore
class Transaction:
"""A transaction guard. This is really just
syntactic suggar arount a memento closure.
"""
deep= False
def __init__(self,*targets):
self.targets= targets
self.Commit()
def Commit(self):
self.states= [Memento(target,self.deep) for target in self.targets]
def Rollback(self):
for st in self.states:
st()
class transactional(object):
"""Adds transactional semantics to methods. Methods decorated with
@transactional will rollback to entry state upon exceptions.
"""
def __init__(self, method):
self.method= method
def __get__(self, obj, T):
def transaction(*args,**kwargs):
state= Memento(obj)
try:
return self.method(obj, *args, **kwargs)
except:
state()
raise
return transaction
class NumObj(object):
def __init__(self, value):
self.value= value
def __repr__(self):
return'<%s: %r>' %(self.__class__.__name__,self.value)
def Increment(self):
self.value+=1
@transactional
def DoStuff(self):
self.value= '1111' # <- invalid value
self.Increment() # <- will fail and rollback
if __name__ =='__main__':
n= NumObj(-1)
print(n)
t= Transaction(n)
try:
for i in range(3):
n.Increment()
print(n)
t.Commit()
print('-- commited')
for i in range(3):
n.Increment()
print(n)
n.value+='x' # will fail
print(n)
except:
t.Rollback()
print('-- rolled back')
print(n)
print('-- now doing stuff ...')
try:
n.DoStuff()
except:
print('-> doing stuff failed!')
import traceback
traceback.print_exc(0)
pass
print(n)
7.解释器模式
1.概念
是什么?:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。通过不同的解释器可以对相同的上下文环境进行解释。
为什么?:当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。
2.代码
class Context:
def __init__(self):
self.input=""
self.output=""
class AbstractExpression:
def Interpret(self,context):
pass
class Expression(AbstractExpression):
def Interpret(self,context):
print("terminal interpret")
class NonterminalExpression(AbstractExpression):
def Interpret(self,context):
print("terminal interpret")
if __name__ =="__main__":
context=""
c= []
c= c + [Expression()]
c= c + [NonterminalExpression()]
c= c + [Expression()]
c= c + [Expression()]
for a in c:
a.Interpret(context)
8.状态模式
1.概念
是什么?: 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
为什么?:一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
2.代码
class State(object):
"""Base state. This is to share functionality"""
def scan(self):
"""Scan the dial to the next station"""
self.pos+=1
if self.pos ==len(self.stations):
self.pos= 0
print("Scanning... Station is",self.stations[self.pos],self.name)
class AmState(State):
def __init__(self, radio):
self.radio= radio
self.stations= ["1250","1380", "1510"]
self.pos= 0
self.name= "AM"
def toggle_amfm(self):
print("Switching to FM")
self.radio.state= self.radio.fmstate
class FmState(State):
def __init__(self, radio):
self.radio= radio
self.stations= ["81.3","89.1", "103.9"]
self.pos= 0
self.name= "FM"
def toggle_amfm(self):
print("Switching to AM")
self.radio.state= self.radio.amstate
class Radio(object):
"""A radio. It has a scan button, and an AM/FM toggle switch."""
def __init__(self):
"""We have an AM state and an FM state"""
self.amstate= AmState(self)
self.fmstate= FmState(self)
self.state= self.amstate
def toggle_amfm(self):
self.state.toggle_amfm()
def scan(self):
self.state.scan()
# Test our radio out
if __name__ =='__main__':
radio= Radio()
actions= [radio.scan]* 2 + [radio.toggle_amfm] +[radio.scan] *2
actions= actions * 2
for action in actions:
action()
9.策略模式
1.概念
是什么?:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
为什么?: 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时[H087] ,可以使用策略模式。算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
2.代码
"""
Strategy
In most of other languages Strategy pattern is implemented via creating some base strategy interface/abstract class and
subclassing it with a number of concrete strategies (as we can see at http://en.wikipedia.org/wiki/Strategy_pattern),
however Python supports higher-order functions and allows us to have only one class and inject functions into it's
instances, as shown in this example.
"""
import types
class StrategyExample:
def __init__(self, func=None):
self.name= 'Strategy Example 0'
if func is not None:
self.execute= types.MethodType(func,self)
def execute(self):
print(self.name)
def execute_replacement1(self):
print(self.name+ ' from execute 1')
def execute_replacement2(self):
print(self.name+ ' from execute 2')
if __name__ =='__main__':
strat0= StrategyExample()
strat1= StrategyExample(execute_replacement1)
strat1.name= 'Strategy Example 1'
strat2= StrategyExample(execute_replacement2)
strat2.name= 'Strategy Example 2'
strat0.execute()
strat1.execute()
strat2.execute()
10.责任链模式
1.概念
是什么?: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
为什么?:有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 可处理一个请求的对象集合应被动态指定。
2.代码
class Handler:
def successor(self, successor):
self.successor = successor
class ConcreteHandler1(Handler):
def handle(self, request):
if request > 0 and request <= 10:
print("in handler1")
else:
self.successor.handle(request)
class ConcreteHandler2(Handler):
def handle(self, request):
if request > 10 and request <= 20:
print("in handler2")
else:
self.successor.handle(request)
class ConcreteHandler3(Handler):
def handle(self, request):
if request > 20 and request <= 30:
print("in handler3")
else:
print('end of chain, no handler for {}'.format(request))
class Client:
def __init__(self):
h1 = ConcreteHandler1()
h2 = ConcreteHandler2()
h3 = ConcreteHandler3()
h1.successor(h2)
h2.successor(h3)
requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]
for request in requests:
h1.handle(request)
if __name__ == "__main__":
client = Client()
11.访问者模式
1.概念
是什么?:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
为什么?: 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke和Johnson所描述过的“重分解以一般化”的一个很好的例子[OJ93]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。控制子类扩展。模板方法只在特定点调用“hook ”操作(参见效果一节),这样就只允许在这些点进行扩展。
2.代码
class Node(object):
pass
class A(Node):
pass
class B(Node):
pass
class C(A, B):
pass
class Visitor(object):
def visit(self, node,*args, **kwargs):
meth= None
for cls in node.__class__.__mro__:
meth_name= 'visit_'+cls.__name__
meth= getattr(self, meth_name,None)
if meth:
break
if not meth:
meth= self.generic_visit
return meth(node, *args,**kwargs)
def generic_visit(self, node,*args, **kwargs):
print('generic_visit '+node.__class__.__name__)
def visit_B(self, node,*args, **kwargs):
print('visit_B '+node.__class__.__name__)
if __name__ == '__main__':
a =A()
b =B()
c =C()
visitor = Visitor()
visitor.visit(a)
visitor.visit(b)
visitor.visit(c)