热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

设计模式之11个行为型模式

行为型模式概述行为型模式(BehavioralPattern)是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关

行为型模式概述
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化

行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用

通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
行为型简介

职责链模式(Chain of Responsibility)

命令模式(Command)

解释器模式(Interpreter)

迭代器模式(Iterator)

中介者模式(Mediator)

备忘录模式(Memento)

观察者模式(Observer)

状态模式(State)

策略模式(Strategy)

模板方法模式(Template Method)

访问者模式(Visitor)

1.职责链模式

1.1 动机

职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。

链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并使请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,将请求的发送者和请求的处理者解耦。这就是职责链模式的模式动机。

1.2 类图

设计模式之11个行为型模式

Handler: 抽象处理者
ConcreteHandler: 具体处理者
Client: 客户类
1.3 优点

降低耦合度

可简化对象的相互连接

增强给对象指派职责的灵活性

增加新的请求处理类很方便

1.4缺点

不能保证请求一定被接收。

系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。

1.5情景
有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定

在不明确指定接收者的情况下,向多个对象中的一个提交一个请求

动态指定一组对象处理请求

比如

早期的Java AWT事件模型(JDK 1.0及更早)

Java中的异常处理机制
2.命令模式
2.1 动机

命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。

2.2 类图

设计模式之11个行为型模式

Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类

2.3 优点

降低系统的耦合度。

新的命令可以很容易地加入到系统中。

可以比较容易地设计一个命令队列和宏命令(组合命令)。

可以方便地实现对请求的Undo和Redo。

2.4 缺点

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

2.5 情景
系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。

系统需要在不同的时间指定请求、将请求排队和执行请求

系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作

系统需要将一组操作组合在一起,即支持宏命令。

如:委派事件模型

3.解释器模式

4.迭代器模式

5.中介者模式

5.1 动机

在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责

对于一个模块,可能由很多对象构成,而且这些对象之间可能存在相互的引用,为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们需要使用中介者模式,这就是中介者模式的模式动机。

5.2 类图

设计模式之11个行为型模式

Mediator: 抽象中介者
ConcreteMediator: 具体中介者
Colleague: 抽象同事类
ConcreteColleague: 具体同事类

5.3 优点

简化了对象之间的交互。

将各同事解耦。

减少子类生成。

可以简化各同事类的设计和实现。

5.4 缺点

在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护

5.5 情景

系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。

一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象

想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的中介者类。

6.备忘录

6.1动机

在应用软件的开发过程中,很多时候我们都需要记录一个对象的内部状态

在具体实现过程中,为了允许用户取消不确定的操作或从错误中恢复过来,需要实现备份点和撤销机制,而要实现这些机制,必须事先将状态信息保存在某处,这样才能将对象恢复到它们原先的状态。备忘录模式是一种给我们的软件提供后悔药的机制,通过它可以使系统恢复到某一特定的历史状态

6.2类图

设计模式之11个行为型模式

Originator: 原发器
Memento: 备忘录
Caretaker: 负责人

6.3优点

提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用先前存储起来的备忘录将状态复原。

实现了信息的封装,一个备忘录对象是一种原发器对象的表示,不会被其他代码改动,这种模式简化了原发器对象,备忘录只保存原发器的状态,采用堆栈来存储备忘录对象可以实现多次撤销操作,可以通过在负责人中定义集合对象来存储多个备忘录。

6.4缺点

资源消耗过大,如果类的成员变量太多,就不可避免占用大量的内存,而且每保存一次对象的状态都需要消耗内存资源,如果知道这一点大家就容易理解为什么一些提供了撤销功能的软件在运行时所需的内存和硬盘空间比较大了。

6.5情景

保存一个对象在某一个时刻的状态或部分状态,这样以后需要时它能够恢复到先前的状态。

如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过负责人可以间接访问其内部状态

7.观察者模式(Observer)

7.1动机

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

7.2类图

设计模式之11个行为型模式

Subject: 目标
ConcreteSubject: 具体目标
Observer: 观察者
ConcreteObserver: 具体观察者

7.3优点

观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。

观察者模式在观察目标和观察者之间建立一个抽象的耦合

观察者模式支持广播通信观察者模式符合“开闭原则”的要求。

7.4缺点

如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间

如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃

观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

7.5情景

一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用

一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

一个对象必须通知其他对象,而并不知道这些对象是谁需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制

8.状态模式(State)

8.1动机
状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

8.2类图

设计模式之11个行为型模式

Context: 环境类
State: 抽象状态类
ConcreteState: 具体状态类

8.3优点

封装了转换规则

枚举可能的状态,在枚举状态之前需要确定状态种类。

将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。

允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

8.4缺点

状态模式的使用必然会增加系统类和对象的个数

状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱

状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

8.5情景

对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为

代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。

9.策略模式(Strategy)

9.1动机
完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务
9.2类图
设计模式之11个行为型模式

Context: 环境类
Strategy: 抽象策略类
ConcreteStrategy: 具体策略类

9.3优点

策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

策略模式提供了管理相关的算法族的办法

策略模式提供了可以替换继承关系的办法

使用策略模式可以避免使用多重条件转移语句

9.4缺点
客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
9.5情景

如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

一个系统需要动态地在几种算法中选择一种

如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。

如Java SE的容器布局管理

10.模板方法模式(Template Method)

10.1动机
模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中

10.2类图

设计模式之11个行为型模式

AbstractClass: 抽象类
ConcreteClass:  具体子类

10.3优点
模板方法模式在一个类中形式化地定义算法,而由它的子类实现细节的处理

模板方法模式是一种代码复用的基本技术

模板方法模式导致一种反向的控制结构,通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,符合“开闭原则”

10.4缺点
每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。
10.5情景

一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现

各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。

控制子类的扩展

11.访问者模式(Visitor)

11.1动机
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式,这就是访问者模式的模式动机。
11.2类图
设计模式之11个行为型模式11.3优点
使得增加新的访问操作变得很容易

将有关元素对象的访问行为集中到一个访问者对象中,而不是分散到一个个的元素类中。

可以跨过类的等级结构访问属于不同的等级结构的元素类。让用户能够在不修改现有类层次结构的情况下,定义该类层次结构的操作

11.4缺点
增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求。

破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。
11.5情景

一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作。

需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。访问者模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。

对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作


推荐阅读
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 树莓派Linux基础(一):查看文件系统的命令行操作
    本文介绍了在树莓派上通过SSH服务使用命令行查看文件系统的操作,包括cd命令用于变更目录、pwd命令用于显示当前目录位置、ls命令用于显示文件和目录列表。详细讲解了这些命令的使用方法和注意事项。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 本文讨论了在使用sp_msforeachdb执行动态SQL命令时,当发生错误时如何捕获数据库名称。提供了两种解决方案,并介绍了如何正确使用'?'来显示数据库名称。 ... [详细]
author-avatar
mobiledu2502871077
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有