设计模式-行为型

概述

行为型模式用于描述程序在运行时的复杂控制流程,即描述多个类怎样协同完成单个类无法完成的任务。
行为型模式分为类行为型和结构行为型模式,前者采用继承在类之间分派行为;后者使用聚合或者组合在对象之间分派行为。由于聚合关系比继承关系更满足合成复用原则,所以具有更大的灵活性。

行为型模式有11种:

  1. 模板方法模式:定义一个骨架,将某些步骤延迟到子类中去实现,可以在不改变结构的情况下重新定义某些特定步骤。
  2. 策略模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户
  3. 命令模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开
  4. 职责链模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合
  5. 状态模式:允许一个对象在其内部状态发生改变时改变其行为能力
  6. 观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为
  7. 中介者模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解
  8. 迭代器模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示
  9. 访问者模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问
  10. 备忘录模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它
  11. 解释器模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器

以上 11 种行为型模式,除了模板方法模式和解释器模式是类行为型模式,其他的全部属于对象行为型模式,下面我们将详细介绍它们的特点、结构与应用。

1. 模板方法模式

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

优点:

  • 封装了不可变部分,拓展了可变部分,在父类中封装了不可变部分,可变部分便于在子类在红拓展。符合开闭原则。
  • 父类中提取的公共代码便于复用

缺点:

  • 对于每一个不同的实现都要拓展子类,导致子类个数容易膨胀
  • 由于继承的关系,在父类中新增抽象方法,在子类中都要实现

框架中的应用:
JDK的AQS框架

2.策略模式

将一系列算法封装起来,每个算法封装一个为一个子类。有客户端在调用时决定调用哪一个子类。这样可以吧使用算法和实现算法分开。

在这里插入图片描述

优点:

  • 多重条件下减少if-else分支或者switch-case分支
  • 在不修改代码的情况下增加算法,符合开闭原则
  • 实现了算法的使用和算法的实现分离,解耦

缺点:

  • 客户端在调用时要直到每种算法的区别和使用场景,以便选择恰当的算法
  • 策略模式会造成很多的策略子类

在框架中的使用:
Arrays的一个排序方法sort,需要我们传入不同的比较方法,来实现调用不同的排序算法。
public static void sort(T[] a, Comparator<? super T> c)

3.命令模式:

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

在这里插入图片描述
优点:

  • 增加命令或者删除命令很方便,不会对其他类产生影响,满足开闭原则
  • 便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。

缺点:

  • 可能产生大量具体的命令类。因为每一个具体操作都需要设计一个具体命令类,这会增加系统的复杂性
  • 命令模式的结果其实就是接收方的执行结果,但是为了以命令的形式进行架构、解耦请求与实现,引入了额外类型结构(引入了请求方与抽象命令接口),增加了理解上的困难

命令模式和策略模式和状态模式的区别:

  • 策略模式是不同的策略算法做同一件事比如排序
  • 命令模式是不同的命令做不同的事,常含有接收者
  • 状态根据状态的不同自主转换不同的行为,内部有固定的行为链条,要按照这个链条一步一步的来,外界无法也无意干扰状态链。

4.职责链模式

为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

优点:

  • 降低了对象之间的耦合,责任链中的对象只需要知道下一个要传递的对象,但是不需要知道其他处理对象,以及其实现细节,简化了对象之间的依赖关系。符合迪米特法则
  • 可以根据需求新增处理类,可拓展性强,符合开闭原则
  • 可以动态的改变责任链中成员的次序以及数量,增强了系统的灵活性
  • 责任链中的每个成员只需要处理好自理的责任,符合单一职责原则

缺点:

  • 不能保证每个请求都会被处理,有些不符合条件的请求一直穿到责任链末端也不会被请求
  • 如果涉及不当,可能会造成循环调用

在框架中的应用:
spring的拦截器

5.状态模式

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
比如订单状态,某一时刻一定处于某一种状态,处理完之后自动转为下一种状态。

注:
根据状态的不同自主转换不同的行为,内部有固定的行为链条,要按照这个链条一步一步的来,外界无法也无意干扰状态链。

优点:

  • 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
  • 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
  • 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

缺点:

  • 状态的增加会增加状态处理类的个数
  • 状态的结构和实现都比较复杂,如果处理不当会导致程序结构和代码的混乱
  • 对来比原则支持不太好,增加一种状态需要修改状态转换类

6.观察者模式

指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式

降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。

7.中介者模式

定义一个中介对象来封装一系列对象之间的交互,同事对象之间的调用又中介者转发,使原有对象之间的耦合松散,它是迪米特法则的典型应用

结构:
抽象同时类通过中介者接口持有具体中介者,具体同事之间的通讯由中介者代为转发,实现具体同事之间的解耦。
在这里插入图片描述
优点:

  • 类之间各司其职,符合迪米特法则。
  • 降低了对象之间的耦合性,使得对象易于独立地被复用。
  • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。

缺点:

  • 中介者模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。

使用场景:

  • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。

8.迭代器模式

提供一个迭代器对象来访问聚合对象的内部数据,而不暴露聚合对象的内部表示。对客户端隐藏了如何迭代输入的细节。符合迪米特法则,每一个聚合对象有自己的迭代器,符合开闭原则。、

优点:

  • 访问一个对象的内容而无需暴露其内容细节
  • 遍历任务交给迭代器,简化了聚合类
  • 为遍历不同结构的数据提供统一的接口

缺点:

  • 增加了迭代器实现类的个数,一定程度上增加了系统的复杂性

JDK 的Collection、List、Set、Map 都实现 自己的迭代器

9.访问者模式

将对象中的数据的操作分离出来包装成独立的类,在数据不变的情况下给这些数据添加新的操作。采用访问者模式,每个访问者包装了对该数据的一个新的操作。

比如:一个水果,一个人想直接吃,一个人想打成汁喝。这个水果就是数据,人就是访问者,吃和喝着两个对水果的动作分别被封装在这两个访问者上。

结构:
访问者A和B对元素A有不同的操作,分别被封装在A和B两个具体访问者中。
其中元素的个数可以有多个但是要固定不改变。
在这里插入图片描述

优点:

  • 拓展性好,能够在不改变元素的情况下,对元素添加新的功能
  • 灵活性好,将数据结构和作用于数据结构上的操作解耦
  • 每个访问者封装了一个操作,符合单一职责原则

缺点:

  • 新增加元素很困难,在分割访问者中都要增加对于新增元素的操作
  • 具体元素对访问者暴露细节,破坏了封装性
  • 违反了依赖倒置原则,访问者依赖了具体的类,而没有依赖抽象

使用场景:

  • 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。
  • 对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作。

10.备忘录模式

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式

11. 解释器模式

给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值