python设计模式之外观模式

系统会随着演化变得非常复杂,最终形成大量的(并且有时是令人迷惑的)类和交互,这种情况并不少见。许多情况下,我们并不想把这种复杂性暴露给客户端。外观设计模式有助于隐藏系统的内部复杂性,并通过一个简化的接口向客户端暴露必要的部分。本质上, 外观( Facade)是在已有复杂系统之上实现的一个抽象层。

1. 现实生活中的例子

在现实中,外观模式相当常见。当你致电一个银行或公司,通常是先被连线到客服部门,客服职员在你和业务部门(结算、技术支持、一般援助等)及帮你解决具体问题的职员之间充当一个外观的角色。

也可以将汽车或摩托车的启动钥匙视为一个外观。外观是激活一个系统的便捷方式,系统的内部则非常复杂。当然,对于其他可以通过一个简单按钮就能激活的复杂电子设备,同样可以如此看待,比如计算机。

2. 软件的例子

django-oscar-datacash模块是Django的一个第三方组件,用于集成DataCash支付网关。该组件有一个Gateway类,提供对多种DataCash API的细粒度访问。在那之上,它也包含一个Facade类,提供粗粒度API (提供给那些不需要处理细节的人),并针对审计目的提供保存事务的能力。

Caliendo是一个用于模拟Python API的的接口,它包含一个facade模块。该模块使用外观模式来完成许多不同但有用的事情(比如缓存方法),并基于传给顶层Facade方法的输入对象决定返回什么方法。

3. 应用案例

使用外观模式的最常见理由是为一个复杂系统提供单个简单的入口点。引入外观之后,客户端代码通过简单地调用一个方法/函数就能使用一个系统。同时,内部系统并不会丢失任何功能,外观只是封装了内部系统。

不把系统的内部功能暴露给客户端代码有一个额外的好处:我们可以改变系统内部,但客户端代码不用关心这个改变,也不会受这个改变的影响。客户端代码不需要进行任何改变。

如果你的系统包含多层,外观模式也能派上用场。你可以为每一层引入一个外观入口点,并让所有层级通过它们的外观相互通信。这提高了层级之间的松耦合性,尽可能保持层级独立。

假设我们想使用多服务进程方式实现一个操作系统,类似于MINIX 3 那样。多服务进程的操作系统有一个极小的内核,称为微内核( microkernel),它在特权模式下运行。系统的所有其他服务都遵从

一种服务架构(驱动程序服务器、进程服务器、文件服务器等)。每个服务进程属于一个不同的内存地址空间,以用户模式在微内核之上运行。这种方式的优势是操作系统更能容错、更加可靠、更加安全。例如,由于所有驱动程序都以用户模式在一个驱动服务进程之上运行,所以某个驱动程序中的一个bug并不能让整个系统崩溃,也无法影响到其他服务进程。其劣势则是性能开销和系统编程的复杂性,因为服务进程和微内核之间,还有独立的服务进程之间,使用消息传递方式进行通信。消息传递比宏内核(如Linux)所使用的共享内存模型更加复杂。

我们从Server接口①开始实现,使用一个Enum类型变量来描述一个服务进程的不同状态,使用abc模块来禁止对Server接口直接进行初始化,并强制子类实现关键的boot()和kill()方法。这里假设每个服务进程的启动、关闭及重启都相应地需要不同的动作。如果你以前没用过abc模块,请记住以下几个重要事项。

  • [ ] 我们需要使用metaclass关键字来继承ABCMeta。
  • [ ] 使用@abstractmethod修饰器来声明Server的所有子类都应(强制性地)实现哪些

    方法。

可随意改变接口和方法签名来满足你的需求,但要确保在改变之后,客户端代码不需要知道OperatingSystem外观类之外的任何对象 完整代码如下:

from enum import Enum
from abc import ABCMeta, abstractmethod
State = Enum('State', 'new running sleeping restart zombie')
class User:
pass
class Process:
pass
class File:
pass
class Server(metaclass=ABCMeta):
@abstractmethod
def __init__(self):
pass
def __str__(self):
return self.name
@abstractmethod
def boot(self):
pass
@abstractmethod
def kill(self, restart=True):
pass
class FileServer(Server):
def __init__(self):
'''初始化文件服务进程要求的操作'''
self.name = 'FileServer'
self.state = State.new
def boot(self):
print('booting the {}'.format(self))
'''启动文件服务进程要求的操作'''
self.state = State.running
def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止文件服务进程要求的操作'''
self.state = State.restart if restart else State.zombie
def create_file(self, user, name, permissions):
'''检查访问权限的有效性、用户权限等'''
print("trying to create the file '{}' for user '{}' with permissions
{}".format(name, user, permissions))
class ProcessServer(Server):
def __init__(self):
'''初始化进程服务进程要求的操作'''
self.name = 'ProcessServer'
self.state = State.new
def boot(self):
print('booting the {}'.format(self))
'''启动进程服务进程要求的操作'''
self.state = State.running
def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止进程服务进程要求的操作'''
self.state = State.restart if restart else State.zombie
def create_process(self, user, name):
'''检查用户权限和生成PID等'''
print("trying to create the process '{}' for user '{}'".format(name, user))
class WindowServer:
pass
class NetworkServer:
pass
class OperatingSystem:
'''外观'''
def __init__(self):
self.fs = FileServer()
self.ps = ProcessServer()
def start(self):
[i.boot() for i in (self.fs, self.ps)]
def create_file(self, user, name, permissions):
return self.fs.create_file(user, name, permissions)
def create_process(self, user, name):
return self.ps.create_process(user, name)
def main():
os = OperatingSystem()
os.start()
os.create_file('foo', 'hello', '-rw-r-r')
os.create_process('bar', 'ls /tmp')
if __name__ == '__main__':
main()

输出如下:

booting the FileServer
booting the ProcessServer
trying to create the file 'hello' for user 'foo' with permissions - rw-r-r
trying to create the process 'ls /tmp' for user 'bar'

外观类OperatingSystem起到了很好的作用。客户端代码可以创建文件和进程,而无需知

道操作系统的内部细节,比如,多个服务进程的存在。准确点说是客户端可以调用方法来创建文

件和进程,但是目前它们是模拟的。

5. 小结

本章中,我们学习了如何使用外观模式。在客户端代码想要使用一个复杂系统但又不关心系统复杂性之时,这种模式是为复杂系统提供一个简单接口的理想方式。一台计算机是一个外观,因为当我们使用它时需要做的事情仅是按一个按钮来启动它;其余的所有硬件复杂性都用户无感知地交由BIOS、引导加载程序以及其他系统软件来处理。现实生活中外观的例子更多,比如,我们所致电的银行或公司客服部门,还有启动机动车所使用的钥匙。

python设计模式之外观模式的更多相关文章

  1. Python设计模式之"外观模式"实例讲解

    Python中设计模式之外观模式主张以分多模块进行代码管理而减少耦合,下面用实例来进行说明. 应用特性: 在很多复杂而小功能需要调用需求时,而且这些调用往往还有一定相关性,即一调用就是一系列的. 结构 ...

  2. python : 设计模式之外观模式(Facade Pattern)

    #为啥要用外观模式举例说明 这个例子很形象,直接从人家博客上贴过来的,参考链接在下面 不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶.茶具和开水,如图1(A)所示,而 ...

  3. Python设计模式(9)-外观模式

    # /*外观模式:为外界调用提供一个统一的接口,把其他类中需要用到的方法提取# * 出来,由外观类进行调用.然后在调用段实例化外观类,以间接调用需要的# * 方法.这种方式和代理模式有异曲同工之妙.然 ...

  4. 每天一个设计模式-2 外观模式(Facade)

    每天一个设计模式-2  外观模式(Facade) 1.生活中的示例 客户想要购买一台电脑,一般有两种方法: 1.自己DIY,客户需要知道组成电脑的所有电子器件,并且需要熟悉那些配件,对客户要求较高. ...

  5. C#设计模式(11)——外观模式(Facade Pattern)

    一.引言 在软件开发过程中,客户端程序经常会与复杂系统的内部子系统进行耦合,从而导致客户端程序随着子系统的变化而变化,然而为了将复杂系统的内部子系统与客户端之间的依赖解耦,从而就有了外观模式,也称作 ...

  6. 乐在其中设计模式(C#) - 外观模式(Facade Pattern)

    原文:乐在其中设计模式(C#) - 外观模式(Facade Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 外观模式(Facade Pattern) 作者:webabcd 介绍 ...

  7. 设计模式之 外观模式详解(Service第三者插足,让action与dao分手)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,LZ今天给各位分享一 ...

  8. 8.4 GOF设计模式三: 外观模式 Facade

    GOF设计模式三: 外观模式 Facade  “现有系统”功能强大.复杂,开发“新系统”需要用到其中一部分,但又要增加一部 分新功能,该怎么办?4.1 Facade Pattern: Key Fea ...

  9. Python设计模式之MVC模式

    # -*- coding: utf-8 -*- # author:baoshan quotes = ('A man is not complete until he is married. Then ...

随机推荐

  1. node.js day01学习笔记:认识node.js

    Node.js(JavaScript,everywhere) 1.Node.js 介绍 1.1. 为什么要学习Node.js 企业需求 + 具有服务端开发经验更好 + front-end + back ...

  2. 详解Vue大护法——组件

    1.什么是组件化 人面对复杂问题的处理方式: 任何一个人处理信息的逻辑能力都是有限的 所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆的内容. 但是,我们人有一种天生的能力,就是将问题进 ...

  3. [redis] -- 持久化机制篇

    快照(snapshotting)持久化(RDB) 该方式是redis默认 持久化方式 Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本.Redis创建快照之后,可以对快照进行备 ...

  4. 商品表(spu)、规格表(sku)设计

    1. 先做一下专业术语解释:spu和sku 这里拿iphone6s举例,它身上有很多的属性和值, 比如: 毛重: 420.00 g 产地: 中国大陆 容量: 16G, 64G, 128G 颜色: 银, ...

  5. ‘100%’wuxiao

    有时候设置控件的width:’100%‘无效,  群友解释, 因为父控件的大小要靠自空间撑起来,确定    ??????

  6. 【新生学习】第一周:深度学习及pytorch基础

    DEADLINE: 2020-07-25 22:00 写在最前面: 本课程的主要思路还是要求大家大量练习 pytorch 代码,在写代码的过程中掌握深度学习的各类算法,希望大家能够坚持练习,相信经度过 ...

  7. 初学Vue.js,用 vue ui 创建项目会不会被鄙视

    全栈的自我修养: 6使用vue ui进行vue.js环境搭建 It is only with the heart that one can see rightly. What is essential ...

  8. R 数据读取与写入

    路径 getwd() #获取当前工作路径 setwd() #设置工作路径 获取普通文本数据 x = read.table("data.txt") #通过路径直接获取 x = rea ...

  9. 详解 awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}每个字段的意思

    用这个列子说好了如果NF代表字段 那最后应该是7 才对啊 还有最后怎么都是1呢?END前面的是查看并发吧 后面是查看 tcp连接数 是这样吗?       awk下标采用字符串来表示可能你在其它语言见 ...

  10. Android:自定义BaseActivity基类

    使用BaseActivity可以封装一些重复代码例如设置标题栏颜色,封装一些工具类... 主要功能: 封装Toast 新建一个BaseActivity继承自Activity package com.o ...