设计模式 ③ — 行为型模式

模板方法模式(TEMPLATE METHOD)

介绍:

知道一个算法的关键步骤,并确定了这些步骤的执行顺序,但不用的程序步骤是不一样的,解决方案就是模板方法模式。

定义:

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

使用场景:

1.多个子类有公有的方法,逻辑基本相同时。

2.重要、复杂的算法,可以把核心算法设计为模板方法,周边细节功能由子类实现。

3.重构时,模板方法模式是一个常用模式,把相同代码抽到父类中,通过钩子函数约束其行为。

UML图:


优点:

1. 封装不变的部分,扩展可变的部分。

2. 提取公共部分代码,便于维护。

缺点:

增加阅读的难度。

观察者模式(OBSERVER)

基础概念:

介绍:

观察者模式是一个使用率非常高的模式,最重要的作用就是解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。

定义:

定义对象间一对多的依赖关系,使得每当一个对象改变状态,则所有依赖它的对象都会得到通知并自动更新。

使用场景:

1.关联行为场景,需要注意的是,关联行为是可拆分的,而不是组合的关系。

2.跨系统的消息交换场景,如消息队列,事件总线的处理机制。

UML图:


Observer : 

抽象观察者,角色的观察者的抽象类,定义了一个更新接口, 主题的更改时通知更新自己。

ConcreteObserver : 

具体的观察者,该角色实现抽象观察者角色所定义的更新接口,在主题状态变化时更新自身状态。

Android源码里的实现:

Adapter的notifyDataSetChaned()方法

优点:

解耦,灵活性和扩展性。

缺点:

开发效率和运行效率的问题,多个观察者存在时开发和调试的内容会比较复杂。

状态模式(STATE)

基础概念:

介绍:

状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。

定义:

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

使用场景:1. 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。

2.代码中包含大量与对象状态有关的条件语句


UML图:


Context : 环境类,定义客户感兴趣的接口,维护一个State子类实例

State : 抽象状态类或者状态接口,定义一个或一组接口,表示该状态下的行为

ConcreteStateA ConcreteStateB : 具体状态类,实现每个具体的行为

Android源码里的实现:

WIFI管理中的开关

优点:

将繁琐的状态判断结构整理的清晰。

缺点:

增加类的数量和个数。

策略模式(STRATEGY)

基础概念:

介绍:

实现一个功能可能会有多种算法和策略,如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法和策略有不同的实现类,在程序客户端就可以通过注入不同的对象来实现算法和策略的动态替换,这种模式的可扩展性,可维护性就更高,就是策略模式。

定义:

策略模式定义了一系列的算法,并将每个算法封装起来,它们还可以相互替换。

使用场景:

1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。

2.需要安全的封装多种同一类型的操作时。

3.同一抽象类有多个子类,又需要使用if-else或者switch来选择具体子类时。

UML图:


Context : 用来操作策略的上下文环境。

Stragety : 策略的抽象。

ConcreteStragetyA ConcreteStragetyB : 具体的策略实现。

Android源码里的实现:

动画插值器,TimeInterpolator。

优点:

结构清晰,耦合度低,封装更彻底,数据更安全。

缺点:

子类繁多。

责任链模式(Chain Of Responsibility)

介绍:

行为型设计模式之一将一个请求从链式的首端发出,沿着链的路径依次传递给每个节点对象,直到有对象处理这个请求为止,这样的模式叫做责任链模式。 

定义:

使多个对象有机会处理请求,避免了请求和发送者和接受者的耦合关系,将这些对象连城一条链,并沿着这条链传递该请求,直到有对象处理它为止。 

使用场景:

多个对象可以处理同一请求,具体由哪个对象处理则在运行时动态决定。

在请求处理者不明确的情况下向多个对象中的一个提交一个请求。

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

UML图:


Handler:处理者角色,声明一个请求处理的方法,保持对下一个处理节点Handler对象的引用。

ConcreteHandler:处理者角色,对请求进行处理,如果不能处理就转发给下一个节点上的处理角色。


Android源码里的实现:

事件分发的处理,如:ViewGroup通过dispatchTouchEvent将事件派发到View。

优点:

请求者和处理者关系解耦,提高代码灵活性。

缺点:

遍历过多,影响性能。

命令模式(COMMAND)

介绍:

命令模式是行为型设计模式之一。将一系列的方法调用封装,用户只需要调用一个方法执行,那么所有这些被封装的方法就会被挨个执行调用。

定义:

将一个请求封装成一个对象,从而使用户使用不同的请求吧客户端参数化,对请求排队或者记录请求日志,以及可撤销的操作。

使用场景:

 需要抽象出待执行的动作,然后以参数的形式提供出来,类似于过程设计中的回调机制,而命令模式是毁掉机制的一个面向对象的替代品。

UML图:


Receiver: 接受者角色。(处理按钮方法的角色,游戏本身)

Command: 命令角色。(执行具体命令的逻辑方法)

ConcreteCommand: 具体命令角色。(按钮方法里的逻辑)

Invoker: 请求者角色。(俄罗斯方块的四个控制按钮)

Client: 客户端角色。(玩游戏的人)

优点:

弱耦合,更好的扩展性。

缺点:

类的膨胀,大量衍生类的创建。

访问者模式(VISITOR)

介绍:

知道一个算法的关键步骤,并确定了这些步骤的执行顺序,但不用的程序步骤是不一样的,解决方案就是模板方法模式。 

定义:

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

使用场景:

1.多个子类有公有的方法,逻辑基本相同时。

2.重要、复杂的算法,可以把核心算法设计为模板方法,周边细节功能由子类实现。

3.重构时,模板方法模式是一个常用模式,把相同代码抽到父类中,通过钩子函数约束其行为。

UML图:


Visitor : 接口或者抽象类,定义了每个元素访问的行为,

ConcreteVisitor : 具体访问者,给出对每个元素类访问时所产生的具体行为。

Element : 元素接口或抽象类,定义一个接受访问者方法,每个元素都要可以被访问者访问。

ElementA ElementB : 具体的元素类,它提供接受访问方法的具体实现,这个具体实现,通常情况下是使用访问者提供的访问该元素类的方法。

ObjectStructure : 定义当中提到的对象结构,对象结构是一个抽象表述,内部管理了元素集合,可以迭代这些元素供访问者访问。

Android源码里的实现:

Android里的注解。

优点: 

1. 各角色职责分离,符合单一职责原则。

2. 优秀的扩展性。

3. 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。

4. 灵活性。

缺点:

1. 对访问者公布细节,违反了迪米特原则。

2. 具体元素变更时导致修改成本大。

3. 违反了依赖倒置原则,为了达到区别对待而依赖了具体类,没有依赖抽象。

中介者模式(MEDIATOR)

介绍:

中介者会知道所有的节点,这些节点可以互不相关,中介者不属于同事的任何一方,也不偏袒任何一方,也称为调节者或者调停者模式。

定义:

中介者模式将多对多的相互作用转化为一对多的相互作用。

使用场景:

对象之间交互操作很多每个对象的行为彼此依赖时,可以使用终结者模式,解决紧耦合问题。该模式将对象的多对多关系变成一对多关系。

UML图:


Mediator :抽象中介者角色,定义了同事对象到中介者对象的接口。

ConcreteMediator :具体中介者角色,实现中介者方法,向同事发出指令

Colleague :抽象同事类角色,定义中介者对象的接口,它知道中介者不知道其他对象。

ConcreteColleagueA/B :具体同事角色

Android源码里的实现:

Android里的Keyguard锁屏功能的实现。

优点: 

一个类必然会和其他几个类产生依赖关系,中介者模式可以解耦让逻辑结构清晰。

缺点:

如果对本不复杂的依赖关系使用中介者模式会让逻辑结构变的复杂。

备忘录模式(MEMENTO)

介绍:

备忘录模式是一种行为模式,该模式用于保存对象当前状态,并且在之后恢复到这种状态。目的是为了保护好被保存对象状态的完整性及内部实现不向外暴露。

定义:

不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以后就可以将该对象恢复到原先保存的状态。

使用场景:

1.需要保存一个对象在某个时刻的状态或部分状态。

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

UML图:


Originator : 负责创建一个备忘录,可以记录,恢复自身的状态。

Memento : 备忘录角色,存储Originator的内部分享,防止Originator以外的对象访问Memento.

Caretaker : 负责存储备忘录,不能对备忘录内容进行操作和访问,只能将备忘录传给其他对象。

Android源码里的实现:

Activity里的onSaveInsanceState 与onRestoreInstanceState。

优点:

实现了信息的封装,用户不需要关心状态的保存细节。

缺点:

消耗资源,每次保存都会消耗一定的内存

迭代器模式(ITERATOR)

介绍:

迭代器模式又称游标模式,是行为型设计模式。

定义:

提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示。

使用场景:

遍历一个容器对象时。

UML图:


Iterator : 迭代器接口

Concrete Iterator : 具体迭代器类

Aggregate : 容器接口

Concrete Aggregate : 具体容器类

Client : 客户类

Android源码里的实现:

数据库查询Cursor。

优点: 

支持以不用的方式去遍历一个对象。

缺点:

缺点就是类文件的增加。

解释器模式(INTERPRETER)

基础概念:

介绍:

解释器模式是用的比较少的行为型模式之一,提供了一种解释语言的语法或表达式的方式,该模式定义了一个表达式接口,通过该接口解释一个特定的上下文。

定义:

给定一个语言(如由abcdef六个字符组成的字符串集合) , 定义它的文法的一种表示(如S::=cd),并定义一个解释器,该解释器使用该表示来解释语言中的句子。

使用场景:

1.某个简单的语言需要解释执行而且可以将该语言中的语句表示为一个抽象语法树时可以考虑使用解释器模式。

2.在某些特定的领域出现不断重复的问题时,可以将该领域的问题转化为一种语法规则下的语句,然后构建解释器来解释该语句。


UML图:

AbstractExpression : 抽象表达式

TerminalExpression : 终结符表达式

NonterminalExpression : 非终结符表达式

Android源码里的实现:

Android通过PackageParser类解析AndroidManifest文件,PackageParser对AndroidManifest每个组件标签了相应的类用于存储相应的信息。

优点:

扩展性佳,对现有文法扩展时,只需要增加对应的非终结符解释器。

构建抽象语法树时,使用新增的解释器对象进行具体的解释即可。

缺点:

每个文法生成一个类,后期维护困难,对于复杂的文法不推荐使用解释器模式。

你可能感兴趣的:(设计模式 ③ — 行为型模式)