外观模式:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
外观模式的核心在于将复杂的内部实现包装起来,只向外界提供简单的调用接口。类似现实世界中的电脑,开机按钮可以说就是一个简单的调用接口,帮用户屏蔽了复杂的内部电路。
**外观设计模式 **—— 有助于隐藏系统的内部复杂性,并且通过一个简化的接口向客户端暴露必要的部分。本质上,外观是在已有复杂系统之上实现的一个抽象层。
(1)实现了子系统与客户端之间的松耦合关系。
(2)客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易。
(3)这其实也是Python一直提倡的封装思想,隐藏一些丑陋的系统,提供API去调用,不用管内部如何实现,只需调用API即可实现相关功能。
其缺点在于不能很好地限制客户使用子系统类,而且在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
外观模式跟代理模式有点像,都是在client和目标的类之间建一个中间的类,client不直接调用目标的类,而是通过先调用中间类的方法,由中间类来实现怎么调用目标类。
代理模式用这种模式的目的是可以实现client和目标类不直接通信,使他们之间相互独立,这样就比较安全,因为client不知道目标类的存在。
外观模式的目的是通过建立一个中间类,把调用目标类的代码都封装好,例如有时候目标类有很多个,逐一得去调用它们会很麻烦,这样通过中间类封装好的接口,client的调用就会很简单
**适配器模式:**将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
外观模式与适配器模式的区别不是包装的类的多少,而是意图不一样。适配器模式也可以包装很多类,但他的意图是改变接口,符合客户的期望;外观模式是将接口进行简化,方便使用。
1、外观模式对接口进行了简化,但这并不意味着对子系统进行彻底封装。如果有必要,这些子系统的接口还可以继续暴露给客户,这就是所谓的高级功能(或称为自定义)。
2、外观模式不能新增功能,但他可以将某些功能按次序执行。例如先打开DVD,后播放DVD。
3、子系统与外观不是一对一关系,是多对多关系。一个子系统可以拥有多个外观,一个外观可以调用多个子系统。
使用外观模式的最常见理由是为一个复杂系统提供单个简单的入口点。引入外观之后,客户端代码通过简单地调用一个方法/函数就能使用一个系统。同时,内部系统并不会丢失任何功能,外观只是封装了内部系统。
不把系统的内部功能暴露给客户端代码有一个额外的好处:我们可以改变系统内部,但客户端代码不用关心这个改变,也不会受这个改变的影响。客户端代码不需要进行任何改变。
主要用于以下场景:
外观模式包含如下角色: Facade: 外观角色 SubSystem:子系统角色
使用步骤具体也是包含两个步骤:
步骤一:创建子系统角色
步骤二:创建外观角色,该角色为子系统中的一组接口提供一个一致界面
假设有一组火警报警系统,由三个子元件构成:一个警报器,一个喷水器,一个自动拨打电话的装置
代码示例:
"""
步骤1:定义子系统,即三个子元件:一个警报器,一个喷水器,一个自动拨打电话的装置
"""
class AlarmSender(object):
def run(self, msg):
return "产生了高温告警: {}".format(msg)
class WaterSprinker(object):
def run(self):
return "洒水降温"
class Dialer(object):
def run(self, name, phone):
return "拨打值班人:{} 电话: {}".format(name, phone)
"""
步骤二:定义外观类,封装子系统的操作
"""
class EmergencyFacade(object):
def __init__(self):
self.alarm = AlarmSender()
self.water = WaterSprinker()
self.dialer = Dialer()
def run(self, name, phone, msg):
data = []
data.append(self.alarm.run(msg))
data.append(self.water.run())
data.append(self.dialer.run(name, phone))
return data
if __name__ == "__main__":
name = "Bruce"
phone = "210-123456"
msg = "高温告警,请立即处理"
emergency = EmergencyFacade()
resp = emergency.run(name, phone, msg)
print(resp)
代码输出:
['产生了高温告警: 高温告警,请立即处理', '洒水降温', '拨打值班人:Bruce 电话: 210-123456']