行为型模式

行为型模式

行为型模式如果按照类之间的关系来分,大致有四种:

  • 父类与子类:策略模式、模板方法模式
  • 两个类之间:观察者模式、迭代子模式、职责链模式、命令模式
  • 类的状态:备忘录模式、状态模式
  • 通过中间类:访问者模式、中介者模式,解释器模式

一、策略模式(本质:分离算法,选择实现)

策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的对立的类中,从而使他们可以相互替换。策略模式可以使得算法在不影响客户端的情况下发生变化。

策略模式中的三种角色:

  • 环境角色(Context)角色:持有一个Strategy类的引用(上下文对象),复杂和具体策略类交互。
  • 抽象策略角色(Strategy):抽象角色,通常由一个接口或抽象类实现,此角色给出所有的具体策略类所需的接口。
  • 具体策略角色(ConcreteStrategy):包装了相关的算法或行为

模式讲解:

  • 策略模式功能:把具体算法从具体业务处理中独立出来
  • 策略模式与if-else语句:多个if-else出现考虑使用策略模式
  • 算法的平行性:策略模式是形同行为的不同实现
  • 谁来选择具体策略算法:客户端、由山下文来选择具体策略

优点:

  • 策略模式可以避免让客户端涉及不必要接触到的复杂的和只与算法有关的数据
  • 避免使用难以维护的多重条件选择语句
  • 更好的扩展

缺点:

  • 把分支判断又放回客户端,需要改变需求算法时,还是要去更改客户端程序
  • 客户端必须知道所有策略类,并自行决定使用哪个策略类,即可用户端必须理解这些算法区别,以便选择恰当的策略类。
  • 增加了对象的数目
  • 只适合扁平的算法结构

二、模板方法模式(本质:固定算法骨架)

模板方法模式:定义一个操作中算法的骨架,而将一些步骤延迟到子类。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的特定步骤。

模板方法模式中两种角色:

  • 抽象模板角色(AbstractClass):定义了一个或多个抽象操作,以便让子类实现,这些抽象操作叫做基本操作,他们是一个顶级逻辑的组成步骤。定义并实现了一个模板方法,这个模板方法一般是一个具体方法,它给出 一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
  • 具体模板角色(ConcreateClass):实现父类所定义的一个或多个抽象方法,他们是一个顶级逻辑的组成步骤。每个抽象模板角色都可以有任意多个具体模板与之对应,而每一个具体模板角色都可以给出这些抽象方法的不同实现,

优点:

  • 实现代码复用

缺点:

  • 算法骨架不容易升级,模板和子类是非常耦合的,若对模板中的算法骨架进行变更,会影响子类变化

三、观察者模式(本质:触发联动)

观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化是,会通知所有观察者对象,使它们自动更新自己。

观察者模式别名:模型-视图模式、源-监听模式、从属者模式。

观察者模式中四种角色:

  • 抽象主题角色(Subject):一个目标可以被多个观察者观察,目标提供对观察者注册和退订的维护,当目标的状态发生改变时,目标负责通知所有注册、有效地观察者
  • 抽象观察者角色(Observer):为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
  • 具体主题角色(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发送通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。
  • 具体观察者角色(ConcreteObserver):具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,集体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

优点:

  • 观察者模式实现了观察者和目标之间的抽象耦合。
  • 观察者模式实现了动态联动
  • 观察者模式支持广播通信。被观察者会向所有登记过的观察者发出通知。

缺点:

  • 可能会引发无谓的操作
  • 采用广播的方式,补灌观察者需不需要,每个观察者都会被调用update方法

四、迭代器模式

迭代器模式:提供一种方法顺序访问一个聚合对象种的各个元素,而又不暴漏该对象内部表示。
迭代器模式种的四种角色:

  • 抽象迭代器角色(Iterator):定义遍历原色所需要的方法,一般有三个:取得下一个元素的next方法,判断是否遍历结束的hasNext方法,移除当前对象的remove方法。
  • 具体迭代器角色(Concrete Iterator):实现迭代器接口中定义的方法,完成集合的迭代。
  • 容器角色(Aggregate): 一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等
  • 具体容器角色(ConcreteAggregate):就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
    #33
    优点:
  • 它支持以不同的方式遍历一个聚合对象。
  • 迭代器简化了聚合类。
  • 在同一个聚合上可以有多个遍历。
  • 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

缺点:

  • 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

五、职责链模式(本质:分离职责,动态组合)

职责链模式:如果有多个对象有机会处理请求,职责链可使请求的发送者和接受者解耦,请求沿着职责链传递,直到有一个对象处理了它为止。

职责链模式中两种角色:

  • 抽象处理者角色(Handler):定义出一个处理请求的接口。如果需要,接口可以定义出一个方法以设定和返回对下家的引用。这个角色通常由一个抽象类或接口实现。
  • 具体处理者角色(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者司以访问下家。

优点:

  • 请求者和接收者松散耦合
  • 动态组合职责

缺点:

  • 产生很多细粒度对象
  • 不一定能被处理:需要提供默认处理

六、命令模式(本质:封装请求)

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

命令模式中四种角色:

  • 抽象命令类角色(Command):声明执行命令的接口,拥有执行命令的抽象方法 execute()。
  • 具体命令角色(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  • 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

命令允许请求的一方和接收请求的一方能够独立演化。
优点:-

  • 命令模式使新的命令很容易地被加入到系统里
  • 允许接收请求的一方决定是否要否决(Veto) 请求。
  • 能较容易地设计一个命令队列。
  • 可以容易地实现对请求的Undo和Redo。
  • 在需要的情况下,可以较容易地将命令记入日志。
  • 命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
  • 命令类与其他任何别的类一样,可以修改和推广。

七、备忘录模式(本质:保存和恢复内部状态。)

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态并在该对象之外保存这个状态。这样以后就可以利用该保存的状态实施恢复操作。

备忘录模式中三种角色:

  • 源发器(Originator):创建一个备忘录,并存储它的内部状态,也可以使用备忘录来回复其内部状态。
  • 备忘录(Memento):存储源发器的内部状态,备忘录的设计一般可以参考源发器的设计,根据实际需要确定备忘录类中的属性。
  • 负责人(Caretaker):负责人又称管理者,在负责人类中可以存储一个或多个备忘录对象,他只负责存储对象而不能修改对象,也无需知道对象细节。

优点:

  • 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但必须要由发起人对象自己读取。这时,备忘录模式可以把复杂的发起人内部信息对其它对象屏蔽起来,从而可以恰当的保持分装的便捷性。
  • 本模式简化了发起人类。发起人不再需要管理何保存其内部的一个个版本,客户端可以自行管理他们所需要的这些状态的版本
  • 当发起人角色的状态改变的时候,有可能这个状态无效,这时候可以使用暂时存储起来的备忘录将状态恢复

缺点:

  • 如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很大。
  • 当管理者角色将-一个备忘录存储起来的时候,管理者可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很大。

八、状态模式(本质:根据状态来分离和选择行为、状态模式是状态驱动,由上下文负责。)

状态模式:创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

状态模式:

  • 允许一个对象在其内部状态改变时改变它的行为,这个对象看起来似乎修改了它的类。
  • 状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表系不同状态的一系列类当中,可以把复杂的逻辑简化。
  • 每个人、事务在不同的状态下会有不同表现动作,而一个状态又会在不同的表现下转移到写一个不同的状态。
  • 在State模式中我们将状态逻辑和动作实现进行分离。当一个操作中要维护大量的分支语句,并且这些分支依赖于对象的状态。State模式将每一个分支都封装到独立的类中。

优点:

  • 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
  • 消除庞大的条件分支语句,把各种状态转移逻辑分布到State的子类之间,减少了相互间的依赖。
  • 显式化进行状态转换:为不同的状态引入独立的对象,使得状态的转换变得更如明确。而且状态对象可以保证上下文不会发生内部状态不一致的状况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。
    缺点:
  • State模式问题主要是逻辑分散化,状态逻辑分布到了很多的State的子类中,很难看到整个的状态逻辑图,这也带来了代码的维护问题。

九、访问者模式(本质:预留通路,回调实现)

访问者模式,将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离。

优点:

  • 访问者模式使得增加新的操作变得很容易,增加新的操作就意味着一个新的访问类。
  • 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。

缺点:

  • 增加新的节点变得很困难。每增加一个节点都意味着要在抽象访问者角色中添加一个新的抽象操作,并再每一个具体访问者类中添加相应的具体操作。
  • 破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有几点对象的要求:对象必须暴漏一些自己的操作和内部状态。

十、中介者模式(本质:封装交互)

中介者模式:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

优点:

  • Mediator模式是一种很有用并且很常用的模式,它通过将对象间的通信封装到一个类中,将多对多的通信转化为一对多的通信,降低了系统的复杂性。
  • Mediator还获得系统解耦的特性,通过Mediator,各个Colleague就不必维护各自通信的对象和通信协议,降低了系统的耦合性,Mediator和各个Colleague就可以相互独立地修改了。
  • Mediator模式还有一个很显著的特点就是将控制集中,集中的优点就是便于管理,也正符合了OO设计中的每个类的职责要单一和集中的原则。

缺点:
由于控制的集中化,于是把交互复杂性变为了中介者的复杂性,这就使得中介者会变得比任何一个ConcreteColleague都复杂。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅梦曾倾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值