设计模式——行为型模式
设计模式——行为型模式
策略模式
当我们写代码时总会遇到一种情况,就是我们会有很多的选择,由此衍生出很多的if…else,或者 case。如果每个条件语句中包含了一个简单的逻辑,那还比较容易处理;但如果在一个条件语句中又包含了多个条件语句,就会使得代码变得臃肿,维护的成本也会加大,这显然违背了开放封闭原则。
定义:定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而独立变化。
在策略模式中有如下角色:
- Context:上下文角色,用来操作策略的上下文环境,起到承上启下的作用,屏蔽高层模块对策略、算法的直接访问。
- Stragety:抽象策略角色,策略、算法的抽象,通常为接口。
- ConcreteStragety:具体的策略实现。
简单实现
张无忌作为一个大侠会遇到很多对手,如果每遇到一个对手他都用自己最厉害的武功去应战,这显然是不明智的。于是张无忌想出了3种应战的策略,分别对付3个实力层次的对手。
定义策略接口
策略接口有一个fighting方法用于战斗:
具体策略实现
分别定义3个策略来实现策略接口,用来对付3个实力层次的对手,代码如下所示:
上下文角色
上下文角色的构造方法包含了策略类,通过传进来不同的具体策略来调用不同策略的fighting方法,如下所示:
客户端调用
张无忌对不同实力层次的对手,采用了不同的策略来应战。为了举例,这里省略了对不同实力层次进行判断的条件语句,代码如下所示。
上面只是举了一个简单的例子,其实情况会很多:比如遇到普通的对手,也不能完全用圣火令神功;比如当遇到周芷若和赵敏时就需要手下留情,采用太极剑;又比如遇到强劲的对手张三丰,由于是自己师公,也不能使用乾坤大挪移。类似这样的情况会很多,这样在每个策略类中可能会出现很多条件语句。但是试想一下如果我们不用策略模式来封装这些条件语句,那么可能会导致一个条件语句中又包含了多个条件语句,这样会使代码变得臃肿,维护的成本也会加大。
使用场景和优缺点
使用场景
- 对客户隐藏具体策略的实现细节,彼此完全独立。
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
- 策略模式将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条件语句。
优点
- 使用策略模式可以避免使用多重条件语句。多重条件语句不易维护,而且易出错。
- 易于拓展。当需要添加一个策略时,只需要实现接口就可以了。
缺点
- 每一个策略都是一个类,复用性小。如果策略过多,类的数量会增多。
观察者模式
观察者模式又被称为发布-订阅模式,属于行为型设计模式的一种,是一个在项目中经常使用的模式。它的定义如下。
定义:定义对象间一种一对多的依赖关系,每当一个对象改变状态时,则所有依赖于它的对象都会得到通知并被自动更新。
在观察者模式中有如下角色:
- Subject:抽象主题(抽象被观察者)。抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题(具体被观察者)。该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,是观察者的抽象类。它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
简单实现
关于观察者模式这种发布-订阅的形式,我们可以拿微信公众号来举例。假设微信用户就是观察者,微信公众号是被观察者。
抽象观察者
里面只定义了一个更新的方法:
具体观察者
微信用户是观察者,里面实现了更新的方法
抽象观察者
抽象被观察者,提供了attach、detach、notify三个方法
具体被观察者
微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法
客户端调用
使用场景及优缺点
使用场景
- 关联行为场景。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
优点
- 观察者和被观察者之间是抽象耦合,容易扩展。
- 方便建立一套触发机制。
缺点
- 在应用观察者模式时需要考虑一下开发效率和运行效率的问题。程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在 Java 中消息的通知一般是顺序执行的,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步方式。
责任链模式
定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,只到有对象处理它为止。