观察者模式用在当一个对象的状态变更需要通知其他很多对象的时候,比如rss订阅或者在社交网站上订阅某个频道的更新。事件驱动系统也是一种发布订阅模式,事件作为发布者,监听器作为订阅者,只不过这里多个事件监听器可以监听同一个事件。 我们这里实现一个“Data Formatter”来解释发布订阅模式,一种数据可以有多个格式化Formatter,当数据更新的时候,会通知所有的Formatter格式化新的数据。使用继承来实现。
......解释器模式用于为高级用户和领域专家提供一个类编程的框架,但没有暴露出编程语言那样的复杂性。这是通过实现一个DSL来达到目的的。
DSL是一种针对特定领域、表达能力有限的计算机语言。 DSL有两类,分别是内部DSL和外部DSL。内部DSL构建在一种宿主编程语言之上,依赖宿主编程语言,外部DSL则是从头实现,不依赖某种已有的编程语言。解释器模式仅与内部DSL相关。
例如:乐谱是一个非软件DSL的例子。音乐演奏者像一个解释器那样,使用乐谱演奏出音乐。
......命令设计模式帮助我们将一个操作(撤销、重做、复制、粘贴等)封装成一个对象,通常是创建一个包含Operation所有逻辑和方法的类。
当我们去餐馆吃饭时,会叫服务员来点单。他们用来做记录的账单(通常是纸质的)就是命令模式的一个例子。在记录好订单后,服务员将其放入账单队列,厨师会照着单子去做。每个账单都是独立的,并且可用来执行许多不同命令,例如,一个命令对应一个将要烹饪的菜品。
通过命令模式可以控制命令的执行时间和过程,还可以用来组织事务。
......责任链(Chain of Responsibility)模式用于让多个对象来处理单个请求,或者用于预先不知道应该由哪个对象(来自某个对象链)来处理某个特定请求。我们可以使用计算机网络的广播来类比责任链模式。
在责任链模式中,发送方可直接访问链中的首个节点。若首个节点不能处理请求,则转发给下一个节点,如此直到请求被某个节点处理或者整个链遍历结束。这种设计模式用于实现发送方与接收方(多个)之间的解耦。
......代理模式是通过一层间接保护层实现更安全的接口访问,例如:访问敏感信息——在允许用户访问敏感信息之前,我们希望确保用户具备足够的权限。
有四种常用的代理模式:
- 远程代理:实际存在于不同地址空间(例如,某个网络服务器)的对象在本地的代理者。使得访问远程对象就像访问本地一样,隐藏了复杂性,如:ORM。
- 虚拟代理:用来实现延迟访问,比如一些需要复杂计算的对象,Python 里可以实现 lazy_property,改善性能。
- 保护/防护代理:用于控制敏感对象的访问。
- 智能(引用)代理:在对象被访问时执行额外的动作。例如引用计数和线程安全检查。
MVC是一个非常重要的设计模式,用于将应用组织成三个部分:模型、视图和控制器。同时,MVC也是一种架构模式,比如流行的 Django 框架就是 MVC(MTV) 模式。
每个部分都有明确的职责。模型负责访问数据,管理应用的状态。视图是模型的外在表现。视图并非必须是图形化的;文本输出也是一种好视图。控制器是模型与视图之间的连接。 MVC的恰当使用能确保最终产出的应用易于维护、易于扩展。
......OOP中容易出现对象创建带来的性能和内存占用问题,当我们想要优化内存使用提高应用性能之时,可以使用享元模式。而想要使享元模式有效,需要满足以下几个条件:
- 需要使用大量对象(Python 中可以使用
__slots__
节省内存使用) - 对象太多难以存储或解析大量对象
- 对象识别不是特别重要,共享对象中对象比较会失败
通常情况下,会使用对象池技术来实现共享对象,比如数据库中经常使用连接池来减少开销,预先建立一些连接池,每次取一个连接和数据库交互。
......一个系统会随着演进而变得非常复杂,最终形成大量的(并且有时是令人迷惑的)类和交互,这种情况并不少见。
但许多情况下,我们并不想把这种复杂性暴露给客户端。而外观设计模式有助于隐藏系统的内部复杂性,并通过一个简化的接口向客户端暴露必要的部分。本质上,外观模式是在已有的系统上实现的一个抽象层。
......当我们想对一个已有的对象添加额外的功能时,可以使用如下方法:
- 如果合理,可以直接将功能添加到对象所属的类(例如,添加一个新的方法)。
- 使用组合
- 使用继承
与继承相比,通常应该优先选择组合,因为继承使得代码更难复用,继承关系是静态的,并且应用于整个类以及这个类的所有实例。
设计模式为我们提供了第四种可选的方法,以支持动态的扩展一个对象的功能,这种方法就是装饰器。
装饰器有很多用途,比如数据校验,事务处理,缓存,日志等。
......适配器模式(Adapter pattern)是一种结构型设计模式,帮助我们实现两个不兼容接口之间的兼容。不兼容接口的含义:如果我们希望把一个老组件用于一个新系统中,或者把一个新组件用于一个老系统中,不对代码进行任何修改两者就能够通信的情况很少见。但又并非总是能修改代码,或因为我们无法访问这些代码(例如,组件以外部库的方式提供),或因为修改代码本身就不切实际。在这些情况下,我们可以编写一个额外的代码层,该代码层包含让两个接口之间能够通信需要进行的所有修改。这个代码层就叫适配器。
现实中最好的例子就是手机充电口,不同型号安卓手机都可以用同样的充电线充电。
......