第5章:可重用性的软件构建方法 5.3面向复用的设计模式

大纲

结构模式

  • Adapter允许具有不兼容接口的类通过将自己的接口包装到已有类的接口中来一起工作。
  • Decorator动态添加/覆盖对象的现有方法中的行为。
  • Facade为大量代码提供简化的界面。

行为模式

  • 策略模式(Strategy)允许在运行时即时选择一个算法族中的一个。
  • 模板(Template)方法将算法的骨架定义为抽象类,允许其子类提供具体行为。
  • 迭代器(Iterator)依次访问对象的元素而不暴露其基础表示。

为什么可重用的设计模式?

一个设计……
…可以灵活地改变(可重用性)
…在修复旧问题时尽量减少引入新问题(可维护性)
…允许在初次交付之后交付更多功能(可扩展性)。

设计模式:软件设计中给定上下文中常见问题的通用,可重用解决方案。
OO设计模式典型地显示类或对象之间的关系和交互,而不指定涉及的最终应用程序类或对象。 除了类本身,设计模式更强调多个类/对象之间的关系和交互过程—比接口/类复用的粒度更大

设计模式分类

创造性模式

  • 关注对象创建的过程

结构模式

  • 处理类或对象的构成

行为模式

  • 描述类或对象交互和分配责任的方式。

结构模式

(1) Adapter

适配器模式(delegation)

适配器模式
意图:将类的接口转换为客户期望获得的另一个接口。将某个类/接口转换为客户期望的其他形式

  • 适配器允许类一起工作,否则因为不兼容的接口而无法工作。
  • 使用新界面包装现有课程。 通过增加一个接口,将已存在的子类封装起来,客户端面向接口编程,从而隐藏了具体子类。

对象:将旧组件重用到新系统(也称为“包装器”)

(2) Decorator

装饰器模式(subtyping and delegation)

使用装饰器模式的例子
假设你想要一个堆栈数据结构的各种扩展……

  • UndoStack:一个堆栈,可以让你撤销先前的推送或弹出操作
  • SecureStack:需要密码的堆栈
  • SynchronizedStack:串行化并发访问的堆栈

和任意可组合的扩展名:

  • SecureUndoStack:需要密码的堆栈,还可以让您撤销先前的操作
  • SynchronizedUndoStack:一个序列化并发访问的堆栈,也可以让你撤消以前的操作
  • SecureSynchronizedStack:…
  • SecureSynchronizedUndoStack:…

装饰器

问题:您需要对单个对象进行任意或动态组合的扩展。为对象增加不同侧面的特性
解决方案:实现通用接口作为要扩展的对象,添加功能,但将主要职责委托给基础对象。 对每一个特性构造子类,通过委派机制增加到对象上
后果:

  • 比静态继承更灵活
  • 可定制的,有凝聚力的扩展

装饰者同时使用子类型和委派

装饰与继承

装饰者在运行时组成功能

  • 继承在编译时组成功能

装饰者由多个协作对象组成

  • 继承产生一个明确类型的对象

可以混合搭配多重装饰

  • 多重继承在概念上是困难的

(3) Facade

外观模式

问题:客户端社区的一部分需要一个简化的界面来实现复杂子系统的整体功能。
即客户端需要通过一个简化的接口来访问复杂系统内的功能
意图提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用

  • 为子系统中的一组接口提供统一接口。 Facade定义了一个更高级别的界面,使得子系统更易于使用。
  • 用更简单的界面包装一个复杂的子系统。

这减少了成功利用子系统所需的学习曲线。便于客户端学习使用,解耦
它还促进了子系统与潜在的许多客户的解耦。

外观模式示例

假设我们有一组具有接口的应用程序来使用MySql / Oracle数据库并生成不同类型的报告,如HTML报告,PDF报告等。
所以我们将有不同的接口集合来处理不同类型的数据库。
现在,客户端应用程序可以使用这些接口来获取所需的数据库连接并生成报告。
但是,当复杂性增加或界面行为名称混淆时,客户端应用程序将难以管理它。
所以我们可以在这里应用Facade模式,并在现有接口的顶部提供一个包装接口来帮助客户端应用程序。

行为模式

(1) Strategy

策略模式

问题:针对特定任务存在不同的算法,但客户端可以根据动态上下文在运行时切换算法。
示例:对客户列表进行排序(冒泡排序,合并排序,快速排序)
解决方案:为算法创建一个接口,并为算法的每个变体实现一个类。
优点:

  • 易于扩展新算法实现
  • 从客户端上下文中分离算法

(2) Template Method

模板方法

问题:多个客户共享相同的算法,但具体细节不同,即算法由可定制的部分和不变的部分组成。 常见的步骤不应该在子类中重复,但需要重新使用。

  • 做事情的步骤一样,但具体方法不同

例子:

  • 执行一组测试用例
  • 打开,阅读,编写不同类型的文件

解:

  • 算法的常见步骤被分解为抽象类,抽象(未实现)基本操作代表算法的可定制部分。共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现
  • 子类为每个步骤提供不同的实现。

模板方法模式

模板方法模式使用继承+可重写方法来改变算法的一部分使用继承和重写实现模板模式

  • 然而策略模式使用委托来改变整个算法(接口和ad-hoc多态性)。

模板方法广泛用于框架

  • 该框架实现算法的不变量
  • 客户端自定义为算法提供专门的步骤
  • 原则:“不要打电话给我们,我们会打电话给你”。

(3) Iterator

迭代器模式

问题:客户需要统一策略来访问容器中的所有元素,而与容器类型无关
解决方案:迭代的策略模式
后果:

  • 隐藏底层容器的内部实现
  • 支持统一接口的多种穿越策略
  • 易于更改容器类型
  • 促进计划各部分之间的沟通

模式结构

  • 抽象迭代器类定义遍历协议
  • 每个聚合类的具体迭代器子类
  • 聚合实例创建Iterator对象的实例
  • 聚合实例保持对Iterator对象的引用

总结

结构模式

  • 适配器允许具有不兼容接口的类通过将自己的接口包装到已有类的接口中来一起工作。
  • 装饰器动态添加/覆盖对象的现有方法中的行为。
  • 外观模式为大量代码提供简化的界面。

行为模式

  • 策略模式允许在运行时即时选择一个算法族中的一个。
  • 模板方法将算法的骨架定义为抽象类,允许其子类提供具体行为。
  • 迭代器依次访问对象的元素而不暴露其基础表示。
    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000015368526
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞