Python 设计模式(第2版) -- 第二部分(结构型模式)
Python 设计模式(第2版)
然后介绍下结构型设计模式。
下面是一些结构型设计模式的例子:
- 适配器模式:将一个接口转换成客户希望的另外一个接口。它试图根据客户端的需求来匹配不同类的接口。
- 桥接模式:该模式将对象的接口与其实现进行解耦,使得两者可以独立工作。
- 装饰器模式:该模式允许在运行时或以动态方式为对象添加职责。我们可以通过接口给对象添加某些属性。
门面模式 – 与门面相适
门面在隐藏内部系统复杂性的同时,为客户端提供了一个接口,以便它们可以非常轻松地访问系统。
假设要在家中举行一场婚礼,必须预订一家酒店或场地,与餐饮人员交代酒菜、布置场景,并安排背景音乐,下面我们从门面模式的角度来看待这些事情。
- 客户端:需要在婚礼前及时完成所有的准备工作。每一项安排都应该是顶级的,这样客人才会喜欢这些庆祝活动。
- 门面:会务经理负责与所有相关人员进行交涉,这些人员负责处理食物、花卉装饰等。
- 子系统:它们代表提供餐饮、酒店管理和花卉装饰等服务的系统。
EventManager 扮演了门面的角色。Hotelier 类用于预订酒店。它有一个方法,用于检查当天是否有免费的酒店(__isAvailable)。Florist 类负责花卉装饰。这个类提供了 setFlowerRequirements() 方法,用于指定要使用哪些种类的花卉来装饰婚礼。Caterer 类用于跟备办宴席者打交道,并负责安排餐饮。Caterer 提供了一个公开的 setCuisine() 法,用来指定婚宴的菜肴类型。 Musician 类用来安排婚礼的音乐,它使用 setMusicType() 方法来了解会务的音乐要求。
class EventManager(object): def __init__(self): print("Event Manager:: Let me talk to the folks\n") def arrange(self): self.hotelier = Hotelier() self.hotelier.bookHotel() self.florist = Florist() self.florist.setFlowerRequirements() self.caterer = Caterer() self.caterer.setCuisine() self.musician = Musician() self.musician.setMusicType() class Hotelier(object): def __init__(self): print("Arranging the Hotel for Marriage? --") def __isAvailable(self): print("Is the Hotel free for the event on given day? ") return True def bookHotel(self): if self. __isAvailable(): print("Registered the Booking\n\n") class Florist(object): def __init__(self): print("Flower Decorations for the Event? --") def setFlowerRequirements(self): print("Carnations, Roses and Lilies would be used for Decorations\n\n") class Caterer(object): def __init__(self): print("Food Arrangements for the Event --") def setCuisine(self): print("Chinese & Continental Cuisine to be served\n\n") class Musician(object): def __init__(self): print("Musical Arrangements for the Marriage --") def setMusicType(self): print("Jazz and Classical will be played\n\n") class You(object): def __init__(self): print("You:: Whoa! Marriage Arrangements? ? ! ! ! ") def askEventManager(self): print("You:: Let's Contact the Event Manager\n\n") em = EventManager() em.arrange() def __del__(self): print("You:: Thanks to Event Manager, all preparations done! Phew! ") you = You() you.askEventManager()
代理模式 – 控制对象访问
代理通常就是一个介于寻求方和提供方之间的中介系统。寻求方是发出请求的一方,而提供方则是根据请求提供资源的一方。
先通过一个简单的例子来理解该模式。不妨以演员与他的经纪人为例,当制作公司想要找演员拍电影时,他们通常会与经纪人交流,而不是直接跟演员交流。
其中 Actor 是代理。对象 Agent 用于查看 Actor 是否正处于忙碌状态。如果 Actor 正忙,则调用 Actor().occupied() 方法;如果 Actor 不忙,则返回 Actor().available() 方法。
class Actor(object): def __init__(self): self.isBusy = False def occupied(self): self.isBusy = True print(type(self). __name__ , "is occupied with current movie") def available(self): self.isBusy = False print(type(self). __name__ , "is free for the movie") def getStatus(self): return self.isBusy class Agent(object): def __init__(self): self.principal = None def work(self): self.actor = Actor() if self.actor.getStatus(): self.actor.occupied() else: self.actor.available() if __name__ == '__main__': r = Agent() r.work()
代理设计模式主要完成了以下工作。
- 它为其他对象提供了一个代理,从而实现了对原始对象的访问控制。
- 它可以用作一个层或接口,以支持分布式访问。
- 它通过增加代理,保护真正的组件不受意外的影响。
这里将通过付款用例来展示代理模式的现实应用场景。假设,你在商场溜达,看中了一件漂亮的牛仔衫。你想买这件衬衫,但手里的现金却不够了。这要是在不久以前,你可以去 ATM 取钱,然后来到商场付款。在更早的时候,通常使用的是银行支票,这样你就必须去银行提款,然后再回商场付款。得益于银行业务的发展,后来出现了一种称为借记卡的东西。所以现在,你买东西的时候,只要在商家刷一下借记卡,这笔钱就会划入商家的账户,从而完成支付。
行为由类 You(即客户端)来表示。该类提供了 make_payment() 方法。主题是 Payment 类。它是一个抽象基类,代表一个接口。具有一个 do_pay() 方法,该方法需要借助代理和真实主题来实现。
Bank 类提供了多个方法来处理付款。代理使用 setCard() 方法将借记卡详细信息发送给银行。由 Bank 类(通过 Payment 接口)实现的 do_pay() 方法实际上负责根据可用资金向商家付款。
DebitCard 类是此处的代理。当你想要付款时,它会调用 do_pay() 方法。DebitCard 类充当真实主题(银行)的代理。
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): @abstractmethod def do_pay(self): pass class Bank(Payment): def __init__(self): self.card = None self.account = None def __getAccount(self): self.account = self.card # Assume card number is account number return self.account def __hasFunds(self): print("Bank:: Checking if Account", self. __getAccount(), "has enough funds") return True def setCard(self, card): self.card = card def do_pay(self): if self. __hasFunds(): print("Bank:: Paying the merchant") return True else: print("Bank:: Sorry, not enough funds! ") return False class DebitCard(Payment): def __init__(self): self.bank = Bank() def do_pay(self): card = input("Proxy:: Punch in Card Number: ") self.bank.setCard(card) return self.bank.do_pay() class You: def __init__(self): print("You:: Lets buy the Denim shirt") self.debitCard = DebitCard() self.isPurchased = None def make_payment(self): self.isPurchased = self.debitCard.do_pay() def __del__(self): if self.isPurchased: print("You:: Wow! Denim shirt is Mine :-)") else: print("You:: I should earn more :(") you = You() you.make_payment()
代理模式的优点:
- 代理可以通过缓存笨重的对象或频繁访问的对象来提高应用程序的性能。
- 代理还提供对于真实主题的访问授权。因此,只有提供合适权限的情况下,这个模式才会接受委派。
- 远程代理还便于与可用作网络连接和数据库连接的远程服务器进行交互,并可用于监视系统。
门面模式和代理模式的比较
代理模式 门面模式 为其他对象提供了代理或占位符,以控制对原始对象的访问 为类的大型子系统提供了一个接口 代理对象具有与其目标对象相同的接口,并保存有目标对象的引用 实现了子系统之间的通信和依赖性的最小化 充当客户端和被封装的对象之间的中介 门面对象提供了单一的简单接口