设计模式——行为型设计模式

文章目录

  • 行为型设计模式
    • 策略模式
    • 模板方法模式
    • 观察者模式
    • 参考资料

行为型设计模式

行为型模式主要处理类或对象如何交互及如何分配职责。

策略模式

策略模式主要用来解决多个 if…else 语句带来的代码变得臃肿问题。多个if…else语句造成维护成本加大,这显然违背了开放封闭原则。

定义:定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换。策略模式使得算法可
独立于使用它的客户而独立变化。

在策略模式中有如下角色。

  • Context:上下文角色,用来操作策略的上下文环境,起到承上启下的作用,屏蔽高层模块对策略、算法的直接访问。
  • Stragety:抽象策略角色,策略、算法的抽象,通常为接口。
  • ConcreteStragety:具体的策略实现。

概述:Context通过多态,调用对应传入对象的方法,从而减少或避免if判断语句。

简单实现
这里仍举武侠的例子。张无忌作为一个大侠会遇到很多对手,如果每遇到一个对手他都用自己最厉害的武功去应战,这显然是不明智的。于是张无忌想出了3种应战的策略,分别对付3个实力层次的对手。

1.定义策略接口

策略接口有一个fighting方法用于战斗:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V7Hk6hMH-1592212983563)(C:\Users\腾腾娃发光的板砖\Desktop\设计模式\策略1.png)]

2.具体策略实现

分别定义3个策略来实现策略接口,用来对付3个实力层次的对手,代码如下所示:

设计模式——行为型设计模式_第1张图片

3.上下文角色
上下文角色的构造方法包含了策略类,通过传进来不同的具体策略来调用不同策略的fighting方法,如下所示:

设计模式——行为型设计模式_第2张图片

4.客户端调用
张无忌对不同实力层次的对手,采用了不同的策略来应战。为了举例,这里省略了对不同实力层次进行判断的条件语句,代码如下所示。

设计模式——行为型设计模式_第3张图片

使用场景

对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
在一个类中定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条件语句。

优点
可以避免使用多重条件语句。多重条件语句不易维护,而且易出错。
易于拓展。当需要添加一个策略时,只需要实现接口就可以了。

缺点
每一个策略都是一个类,复用性小。如果策略过多,类的数量会增多。
上层模块必须知道有哪些策略,才能够使用这些策略,这与迪米特原则相违背。

模板方法模式

某个方法的实现需要多个步骤,其中有些步骤是固定的;而有些步骤并不固定,存在可变性。为了提高代码的复用性和系统的灵活性,可以使用模板方法模式来应对这类情况。

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

在模板方法模式中有如下角色。

  • AbstractClass:抽象类,定义了一套算法框架。
  • ConcreteClass:具体实现类

概述:将子类共有的逻辑提取到父类中作为模板,由子类实现具体的实现

简单实现
模板方法实际就是封装固定的流程,像模板一样,第一步做什么,第二步又做什么,都在抽象类中定义好。子类可以有不同的算法实现,在算法框架不被修改的前提下实现某些步骤的算法替换。

1.创建抽象类,定义算法框架

接着举武侠的例子。 一个武侠要战斗的时候,也有一套固定的通用模式,那就是运行内功、开启经脉、准备武器和使用招式,我们把这些用代码表示,如下所示:

设计模式——行为型设计模式_第4张图片

这个抽象类包含了3种类型的方法,分别是抽象方法、具体方法和钩子方法。抽象方法是交由子类去实现的,具体方法则是父类实现了子类公共的方法。在上面的例子中就是武侠开启经脉的方式都一样,所以就在具体方法中实现。钩子方法则分为两类:第一类在上面代码注释1 处,它有一个空实现的方法,子类可以视情况来决定是否要覆盖它;第二类在注释 2 处,这类钩子方法的返回类型通常是 boolean 类型的,其一般用于对某个条件进行判断,如果条件满足则执行某一步骤,否则将不执行。

2.具体实现类

武侠就拿张无忌、张三丰来作为例子,代码如下所示:

设计模式——行为型设计模式_第5张图片

张无忌没有武器,所以hasWeapons方法返回 false,这样也不会进入 weapons方法了。接下来看张三丰的代码:

设计模式——行为型设计模式_第6张图片

最后,张三丰突然感觉肚子不舒服,所以就实现了钩子方法hook,用来处理一些自定义的逻辑。

3.客户端调用

设计模式——行为型设计模式_第7张图片

使用场景

多个子类有共有的方法,并且逻辑基本相同时。
面对重要、复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现。
需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。

优点

模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
子类实现算法的某些细节,有助于算法的扩展。

缺点

每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。

观察者模式

又被称为发布-订阅模式

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

在观察者模式中有如下角色。

  • Subject:抽象主题(抽象被观察者)。抽象主题角色把所有观察者对象保存在一个集合里,每个主题
    都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者)。该角色将有关状态存入具体观察者对象,在具体主题
    的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者的抽象类。它定义了一个更新接口,使得在得到主题更改通知时更
    新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新
    自身的状态。

概述:将观察者和被观察者都进行抽象,观察者向被观察者注册,一旦被观察者发生某些事件就会立即通知所有观察者。

简单实现

拿微信公众号来举例。假设微信用户就是观察者,微信公众号是被观察者,有多个微信用户关注了一个公众号,当这个公众号更新时就会通知这些订阅的微信用户。接下来用代码实现:

1.抽象观察者
里面只定义了一个更新的方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8BN3Kdt-1592212983573)(C:\Users\腾腾娃发光的板砖\Desktop\设计模式\观1.png)]

2.具体观察者
微信用户是观察者,里面实现了更新的方法,如下所示:

设计模式——行为型设计模式_第8张图片

3.抽象被观察者

抽象被观察者,提供了attach、detach、notify三个方法,如下所示:

设计模式——行为型设计模式_第9张图片

4.具体被观察者

微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题
中的方法:

设计模式——行为型设计模式_第10张图片

(5)客户端调用

设计模式——行为型设计模式_第11张图片

使用场景

关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
事件多级触发场景。
跨系统的消息交换场景,如消息队列、事件总线的处理机制。

优点

观察者和被观察者之间是抽象耦合,容易扩展。
方便建立一套触发机制。

缺点

在应用观察者模式时需要考虑一下开发效率和运行效率的问题。程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在 Java 中消息的通知一般是顺序执行的,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步方式。

参考资料

《Android进阶之光》

你可能感兴趣的:(设计模式)