行为型模式主要处理类或对象如何交互及如何分配职责。
策略模式主要用来解决多个 if…else 语句带来的代码变得臃肿问题。多个if…else语句造成维护成本加大,这显然违背了开放封闭原则。
定义:定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换。策略模式使得算法可
独立于使用它的客户而独立变化。
在策略模式中有如下角色。
概述:Context通过多态,调用对应传入对象的方法,从而减少或避免if判断语句。
简单实现
这里仍举武侠的例子。张无忌作为一个大侠会遇到很多对手,如果每遇到一个对手他都用自己最厉害的武功去应战,这显然是不明智的。于是张无忌想出了3种应战的策略,分别对付3个实力层次的对手。
1.定义策略接口
策略接口有一个fighting方法用于战斗:
2.具体策略实现
分别定义3个策略来实现策略接口,用来对付3个实力层次的对手,代码如下所示:
3.上下文角色
上下文角色的构造方法包含了策略类,通过传进来不同的具体策略来调用不同策略的fighting方法,如下所示:
4.客户端调用
张无忌对不同实力层次的对手,采用了不同的策略来应战。为了举例,这里省略了对不同实力层次进行判断的条件语句,代码如下所示。
使用场景:
对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
在一个类中定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条件语句。
优点:
可以避免使用多重条件语句。多重条件语句不易维护,而且易出错。
易于拓展。当需要添加一个策略时,只需要实现接口就可以了。
缺点:
每一个策略都是一个类,复用性小。如果策略过多,类的数量会增多。
上层模块必须知道有哪些策略,才能够使用这些策略,这与迪米特原则相违背。
某个方法的实现需要多个步骤,其中有些步骤是固定的;而有些步骤并不固定,存在可变性。为了提高代码的复用性和系统的灵活性,可以使用模板方法模式来应对这类情况。
定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类不改变一个算法的结构
即可重定义算法的某些特定步骤。
在模板方法模式中有如下角色。
概述:将子类共有的逻辑提取到父类中作为模板,由子类实现具体的实现
简单实现
模板方法实际就是封装固定的流程,像模板一样,第一步做什么,第二步又做什么,都在抽象类中定义好。子类可以有不同的算法实现,在算法框架不被修改的前提下实现某些步骤的算法替换。
1.创建抽象类,定义算法框架
接着举武侠的例子。 一个武侠要战斗的时候,也有一套固定的通用模式,那就是运行内功、开启经脉、准备武器和使用招式,我们把这些用代码表示,如下所示:
这个抽象类包含了3种类型的方法,分别是抽象方法、具体方法和钩子方法。抽象方法是交由子类去实现的,具体方法则是父类实现了子类公共的方法。在上面的例子中就是武侠开启经脉的方式都一样,所以就在具体方法中实现。钩子方法则分为两类:第一类在上面代码注释1 处,它有一个空实现的方法,子类可以视情况来决定是否要覆盖它;第二类在注释 2 处,这类钩子方法的返回类型通常是 boolean 类型的,其一般用于对某个条件进行判断,如果条件满足则执行某一步骤,否则将不执行。
2.具体实现类
武侠就拿张无忌、张三丰来作为例子,代码如下所示:
张无忌没有武器,所以hasWeapons方法返回 false,这样也不会进入 weapons方法了。接下来看张三丰的代码:
最后,张三丰突然感觉肚子不舒服,所以就实现了钩子方法hook,用来处理一些自定义的逻辑。
3.客户端调用
使用场景:
多个子类有共有的方法,并且逻辑基本相同时。
面对重要、复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现。
需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。
优点:
模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
子类实现算法的某些细节,有助于算法的扩展。
缺点:
每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
又被称为发布-订阅模式。
定义:定义对象间一种一对多的依赖关系,每当一个对象改变状态时,则所有依赖于它的对象都会
得到通知并被自动更新。
在观察者模式中有如下角色。
概述:将观察者和被观察者都进行抽象,观察者向被观察者注册,一旦被观察者发生某些事件就会立即通知所有观察者。
简单实现
拿微信公众号来举例。假设微信用户就是观察者,微信公众号是被观察者,有多个微信用户关注了一个公众号,当这个公众号更新时就会通知这些订阅的微信用户。接下来用代码实现:
1.抽象观察者
里面只定义了一个更新的方法:
2.具体观察者
微信用户是观察者,里面实现了更新的方法,如下所示:
3.抽象被观察者
抽象被观察者,提供了attach、detach、notify三个方法,如下所示:
4.具体被观察者
微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题
中的方法:
(5)客户端调用
使用场景
关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
事件多级触发场景。
跨系统的消息交换场景,如消息队列、事件总线的处理机制。
优点
观察者和被观察者之间是抽象耦合,容易扩展。
方便建立一套触发机制。
缺点
在应用观察者模式时需要考虑一下开发效率和运行效率的问题。程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在 Java 中消息的通知一般是顺序执行的,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步方式。
《Android进阶之光》