前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GoF设计模式快速指南

GoF设计模式快速指南

作者头像
用户1263954
发布2018-01-30 15:04:40
6290
发布2018-01-30 15:04:40
举报
文章被收录于专栏:IT技术精选文摘IT技术精选文摘

关于设计模式

本文主要是对原版GoF的23种设计模式提供一个快速的指南。每个模式的介绍包括了类图,讲解,使用信息和真实案例。

  • 创造型模式(C):用于构造可与系统实现相解耦的对象。
  • 结构型模式(S): 用于生成位于许多不同对象之间的大型对象结构。
  • 行为型模式(B): 用于管理对象间的算法,关系和职责。
  • 对象范围: 处理能够在运行时被改变的对象关系。
  • 类范围: 处理在编译间可被改变的类关系。

C

抽象工厂模式

S

装饰者模式

C

原型模式

S

适配器模式

S

门面模式

S

代理模式

S

桥接模式

C

工厂方法模式

B

观察者模式

C

构建者模式

S

享元模式

C

单例模式

B

责任链模式

B

解释器模式

B

状态者模式

B

命令模式

B

协调者模式

B

模板方法模式

S

复合模式

B

备忘录模式

B

访问者模式

责任链对象行为模式

目的

给一个或多个对象通过将接收对象连接起来去处理一个请求的机会。

什么时候用

  • 多个对象可以处理一个请求,但处理器不一定是一个具体的对象。
  • 一些对象可经运行时决定的处理器去处理一个请求。
  • 一个未被处理的请求是可被接受底层成果。

举例

在一些编程语言对异常处理上就使用了这个模式。当一个异常在方法中被抛出时,运行时检查器就要看这个方法是否有能够处理这个异常的机制或还是决定将其传递给调用栈。当异常被传递给调用栈后,进程就要检查代码直到这个异常被处理或没有父对象再去处理这个请求。

命令对象行为模式

目的

将请求封装为一个对象。也就是允许请求因关系被传统对象处理,如队列和回调。

什么时候用

  • 你需要回调功能。
  • 请求需要在不同的时刻或以不同的顺序被处理。
  • 需求请求的历史。
  • 调用者处理调用时需要与对象解耦。

举例

工作队列被广泛用于实现算法的异步处理。通过将被命令者模式所执行的功能交给一个工作队列来处理,此时队列不需要知晓正在被调用的真实实现是什么。这个被放入队列的命令对象则实现了队列所期望的接口规范的特定算法。

解释器类行为模式

目的

定义了一个语法的呈现以及去理解和执行这个语法的机制。

什么时候用

  • 有个以大型句法树形式存在的语法器去解释语法。
  • 语法是简单的。
  • 效率不重要。
  • 渴望将语法与隐含的表达式相解耦。

举例

在19世纪80年代时,有一个非常流行的基于文本的冒险游戏,这个游戏就是这个模式的好例子。许多简单的命令如按“向下”箭头就可以在游戏中往返移动。这些命令被嵌入用于改变他们的含义。如:“向里”与“向上”就具有不同的结果意义。通过创建一个基于命令的命令等级制度和限定符(非终结和终结表达式),应用可以很容易将许多命令变种映射到一棵行为关系树上。

迭代器对象行为模式

目的

允许访问一个聚集对象的元素而不用访问它的底层呈现。

什么时候用

  • 需要访问元素而不需要访问整个呈现。
  • 需要遍历多个或并发的对象。
  • 需要一个统一的遍历接口。
  • 不同的迭代器的具体实现有所差异。

举例

Java自带的迭代器模式允许用户遍历不同的数据集,而不需要担心集合的底层实现。由于客户端只是简单的与迭代器接口打交道,定义合适的迭代器被交给了集合自身。有些允许完全访问底层的数据集,而有些却对某些特定功能有限制,比如移除元素。

协调者对象行为模式

目的

通过封装不同对象之间交互来做到松耦合。允许将对象的行为设置相互独立。

什么时候用

  • 不同集合对象之间的通信已经被定义好了而且是复杂的。
  • 许多关系已经存在且需要共同的通信或控制点.

举例

邮件列表软件持续追踪谁已经注册了邮件列表而且提供了一个给任何人可与整个列表进行通信的访问单点。没有协调者的实现,一个人想要发送一条消息到组内将需要不断的去检查谁已经或不在邮件列表中。通过实现协调者模式,系统可接收来自任何点的信息来决定转发消息到哪个接收者,没有发送者的消息就需要关注实际的接收者列表。

备忘录对象行为模式

目的

允许捕获和将一个对象的内部状态固有化用于后续可被恢复,所有的这些都不会破坏封装。

什么时候用

  • 一个对象的内部状态必须保存以在后面可被恢复。
  • 当没有暴露实现的时候,内部状态不可通过接口暴露出去。
  • 封装边界必须被保护。

举例

撤消功能就可很好的使用备忘录模式去实现。在状态发生变化前,通过序列和反序列一个对象的状态,我们能够保存一个快照用于在用户选择执行撤消操作时恢复出来。

观察者对象行为模式

目的

用于将系统内其它对象的状态更改通知到一个或多个对象。

什么时候用

  • 一个或多个对象的状态改变能触发其它对象的行为。
  • 需要具备广播消息能力。
  • 有一个共识就是对象是无视通知开销的。

举例

这个模式基本上在每个GUI环境中都可以被找到。当按钮,文本和其它字段框在系统中创建后,系统通常都会为这些控件注册一个监听器。当用户触发了一个事件,比如点击了一个按钮,控制器将会遍历注册了监听这个事件的所有观察者并将通知发给它们。

状态对象行为模式

目的

将对象的环境与行为紧密相连,允许对象基于内部状态有不同的表现行为。

什么时候用

  • 一个对象的行为应该受状态的影响。
  • 复杂的条件将对象的行为和它的状态紧密相连。
  • 状态之间的转换需要明确被确定。

举例

一个邮件对象可以有很多不同的状态,每个状态都驱使对象执行不同的功能。如果状态是“未发送”,则可以调用send()方法发送消息,而recallMessage()方法可能会抛出异常或什么也不做。然而,如果状态是“已发送”,则调用send()方法将会要么抛出异常要么什么也不做,而这时调用recallMessage()则将尝试发送一个recall通知到接收者。为了避免在多数或所有的方法中有条件状态语句,需要有多个状态对象去处理每个特定状态的具体实现。邮件对象内的调用将会被代理到合适的状态对象去处理。

策略对象行为模式

目的

定义一套封装好的算法可用于随时被替换去执行一个具体的行为。

什么时候用

  • 许多相关类的唯一不同只是他们的行为。
  • 需要一个算法的多个版本或变种。
  • 不应该暴露算法存取和使用数据时的代码调用。
  • 一个类的行为需要在运行时被确定。
  • 条件状态语句复杂且难以维护。

举例

当将数据导入到一个新系统时,数据集不同,则需要执行不同的校验算法。通过配置导入,利用策略条件逻辑决定什么需要执行的校验集可被移除,同时导入操作可与实际的校验代码解耦。这允许我们在导入期间可动态调用一个或多个策略。

模板方法类行为模式

目的

定义一个算法的框架,允许实现类去定义真实的行为。

什么时候用

  • 需要一个算法的单一抽象实现。
  • 子类之间的共同行为需要抽到同一个共同类中。
  • 父类能够统一调用子类的行为。
  • 多数甚至所有的子类需要去实现它的行为。

举例

一个父类,像InstantMessage,可能有处理发送一条消息的所有方法。然而,待发送数据的真实序列化可能因实现而不同。一个视频数据和一个文本数据需要不同的算法去正确的序列化。InstantMessage的子类提供自己的序列化方法实现,允许父类调用而不需要理解它们具体的实现。

访问者对象行为模式

目的

允许一个或多个操作可在运行时被用于一套对象身上,将操作与对象的结构相解耦。

什么时候用

  • 一个对象的结构必须要有许多不相关的操作。
  • 对象的结构不可改变但其上的操作却可以。
  • 对象必须被作用于一个对象的具体类。
  • 暴露对象结构的内部状态或操作是可被接受的。
  • 操作能够作用于实现了同一接口的多个对象结构上。

举例

对不同地区的发票进行计税需要许多不同的计算逻辑种类。实现一个访问者可将逻辑从发票和明细支出中解耦出来。这就允许款项的层级可通过计算代码被访问到,然后将地区的适当税率附加上去。这样改变一个地区只需要简单的替换一个不同的访问者。

适配器类和对象结构模式

目的

允许类可通过创建一个可供它们交互的共同对象与该类的不同接口一起工作。

什么时候用

  • 一个将被使用的类不满足接口规范。
  • 复杂的条件将对象的行为和状态捆绑在一起。
  • 状态之间的转换需要明确的确定。

举例

一个账单应用需要与HR应用交互以交换员工数据,而各自都有自己对员工对象的接口和实现。另外,SSN以不同的格式存储在各自系统中。通过创建一个适配器我们可以创建两个应用的共同接口用于通过它们自身的对象进行通信以及能够在进程中传输SSN格式。

桥接对象结构模式

目的

定义一个抽象的对象结构独立于具体的实现类的对象结构以做到限制耦合。

什么时候用

  • 抽象和实现不应该在编译期受约束。
  • 抽象和实现可被独立扩展。
  • 对抽象实现的改变不应该对客户有影响。
  • 具体的实现要对客户不可见。

举例

JVM有它自身一套对视窗系统,系统日志和二进制代码执行的本地功能抽象,然后具体的实现将会被代理到JVM所在运行的操作系统上。当一个应用命令JVM渲染一个窗口,实际上是它将渲染请求代理到JVM所知道可与交互的操作系统的具体实现上去实现对窗口的渲染。

复合对象结构模式

目的

实现对象层级的创建能够使得每个对象可被独立对待或者作为一套可被同一接口嵌入的对象。

什么时候用

  • 需要对象的层级展现。
  • 对象和对象的复合可被统一对待。

举例

有时候购物车里的信息展示只是一个单一产品,而有时候却是一些产品的聚集展示。将产品项实现为一个复合对象,则我们可以将聚集的和普通的产品项同等对待,这样就允许我们可以简单的遍历产品树并调用每个产品项的功能。通过调用任何树结点上的getCall()方法可让我们得到每个项及其子项的所有成本,单一项和组项将被一视同仁。

装饰器对象结构模式

目的

允许动态包装对象用于修改他们已有的职责和行为。

什么时候用

  • 对象的职责和行为需要被动态修改。
  • 具体的实现需要与职责和行为解耦。
  • 子类去实现修改是不切实际或不可行的。
  • 指定的功能不应该位于对象层级的高处。
  • 许多小的对象围绕于一个具体的实现是可被接受的。

举例

许多的公司利用装饰器去设置它们的邮件系统。当公司内部员工发一封邮件给外部接收地址时,邮件服务器则要在原始邮件基础上装饰公司自己的版权和隐私信息。只要邮件还在内部,则这些信息不会被加上。这种装饰允许消息维持不变,直到运行时决定给消息包装一些额外信息为止。

门面对象结构模式

目的

给系统内部的一套接口提供一个单一的接口。

什么时候用

  • 需要提供一个简单的接口来访问一个复杂的系统。
  • 系统实现和客户端之间有许多依赖。
  • 系统和子系统之间需要分层。

举例

通过web服务暴露一组功能给客户端,此时客户端只需要关心暴露给它的那个简单接口而不需要去关心web服务背后不确定的复杂关系。一个简单的web服务请求去更新一个系统的数据可能需要与多个数据库或系统打交道,然而,具体的实现已通过门面模式被隐藏了。

享元对象结构模式

目的

促进许多细粒度对象的重用,从而更高效的使用大量对象。

什么时候用

  • 许多对象已被使用但存储成本很高。
  • 每个对象状态的多数是非固有的。
  • 少许共享的对象可替换许多不能够共享的对象。
  • 每个对象的身份不重要。

举例

允许用户定义他们自身的应用流程和布局的系统通常需要追踪许多几乎相同的字段,页面和其它对象。通过将这些对象轻量化,每个对象的所有实例在分离外在状态时可共享内在化的状态。内在的状态可存储共享的属性,如一个文本框的样子,需要hold住多少数据以及什么事件需要对外暴露。外在状态将存储那些不能共享的属性,如物品属于哪里,如何响应用户的点击以及如何处理事件。

代理对象创建模式

目的

允许通过扮演一个传递实体或占位对象来做到对象级的访问控制。

什么时候用

  • 被展现的对象在系统的外部。
  • 对象需要按需被创建。
  • 需要对原本对象的访问控制。
  • 当一个对象被访问后需要添加额外的功能。

举例

总账应用通常给用户提供了一个按需使得用户银行账单和总账数据一致的方法,处理的过程多数是自动的。而实际它与第三方的通信操作是相对昂贵且需要限制的。通过一个代理去代表通信对象,我们可以限制通信被调用的次数或通信的间隔。另外,我们可以在代理类内包装通信对象的复杂实例,将调用代码与具体的实现相解耦。

抽象工厂对象创建模式

目的

提供一个代理一个或多个具体类的创建请求去生产具体的对象的接口。

什么时候用

  • 对象的创建应该独立于系统对它们的使用。
  • 系统有能力使用对象的多个家族。
  • 对象家族必须一起使用。
  • 库必须被发布而不需要暴露具体的实现。
  • 具体的类要与客户端解耦。

举例

邮件编辑器允许编辑多种格式包括普通文本,富文本和HTML,根据不同的格式,需要创建不同的对象。如果消息是普通文本,则消息将会有一个对象体来代表普通文本和一个附件对象用base64对附件进行加密。如果消息是HTML,则对象体代表了HTML编码后的文本,而附件对象则允许内联呈现一个标准的附件。通过利用抽象工厂来创建,我们可以保证根据邮件需要发送的样式可创建合适的对象集。

构建者对象创建模式

目的

允许基于可易互换的算法来动态的创建对象。

什么时候用

  • 对象的创建算法需要与系统解耦。
  • 需要多个创建算法的呈现。
  • 不改变核心代码的新功能是必要的。
  • 需要运行时控制创建的过程。

举例

一个文件传输应用可能使用了许多不同的协议来发送文件,而真正的传输对象的创建将直接取决于所选择的协议。使用构建器我们可以用正确的构建器去实例化正确的对象。如果设置的是FTP,则FTP的构建器将被用于创建对象。

工厂方法对象创建模式

目的

暴露一个方法用于创建对象,允许子类控制实际的对象创建过程。

什么时候用

  • 一个类不知道什么类需要被创建。
  • 子类可以指定什么对象需要被创建。
  • 父类希望推迟于子类后创建。

举例

许多应用有一些用于安全的用户和组的形式。当应用需要去创建一个用户时,它通常将用户的创建代理到多个用户的实现。父类的用户对象将会处理每个用户的多数操作,但是,子类会定义工厂方法来处理创建每种不同用户的差别。一个系统可能有管理员和普通用户,它们都继承于用户对象。管理员对象可能会执行一些额外的工作来保证访问权限,而普通的用户只会有有限的访问权限。

原型对象创建模式

目的

通过对已有对象来克隆它的模板来创建对象。

什么时候用

  • 创作,创建和展现对象应该与系统解耦。
  • 被创建的类在运行时被指定。
  • 有限的状态组合存在一个对象内。
  • 需要与已存在对象或对象结构相同或近似装配的对象或对象结构。
  • 每个对象的初始创建开销很大。

举例

费用处理引擎通常需要查询许多不同的配置值,初始化这样的引擎相对是一个昂贵的过程。当需要多个这样的引擎实例时,比如以多线程的方式导入数据,则初始化许多这样的引擎的开销是巨大的。通过使用原型模式,我们可以保证只有一个引擎的拷贝被初始化了,然后通过简单的克隆来创建一个已初始化对象的复制品。这种附加的好处就是克隆只需要包括它们自身所需要的相关数据。

单例对象创建模式

目的

确保在一个系统内一个类只有一个实例。

什么时候用

  • 一个类仅仅只需要一个实例。
  • 有必要对一个单类对象进行访问控制。

举例

许多编程语言提供了一些系统或环境对象用于允许该语言与本地的操作系统进行交互。由于应用只是物理运行于仅有的一个操作系统上,那么这个系统对象只需要一个单例。语言运行时实现的单例模式可确保一个系统对象只有一个实例被创建,也能确保适当的操作允许访问它。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT技术精选文摘 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档