- 行为型设计模式主要处理类或对象如何交互及如何分配职责。
6.5.1 策略模式
- 当我们写代码的时候如果出现很多选择,就会使用if…else这种语句。
- 如果这些语句中还包含多个条件语句,那么代码就会变得很臃肿。
- 定义:定义一系列的算法,把每一个算法封装起来,并且使他们可以相互替换。策略模式使算法可独立于使用它的客户而独立变化。
1. 策略模式的简单实现
- 定义策略接口
package com.example.mode2;
public interface FightingStrategy {
public void fighting();
}
- 具体策略实现
package com.example.mode2;
public class WeakRivalStrategy implements FightingStrategy{
@Override
public void fighting() {
System.out.println("遇到了较弱的对手,张无忌使用了太极剑");
}
}
package com.example.mode2;
public class CommonRivalStrategy implements FightingStrategy{
@Override
public void fighting() {
System.out.println("遇到了普通的对手,张无忌使用了圣火令神功");
}
}
package com.example.mode2;
public class StrongRivalStrategy implements FightingStrategy{
@Override
public void fighting() {
System.out.println("遇到了强大的对手,张无忌使用乾坤大挪移");
}
}
- 上下文角色
- 屏蔽高层模块对我们具体实现的算法的直接调用
package com.example.mode2;
public class Context {
private FightingStrategy fightingStrategy;
public Context(FightingStrategy fightingStrategy){
this.fightingStrategy = fightingStrategy;
}
public void fighting(){
fightingStrategy.fighting();
}
}
- 客户端调用
- 张无忌对不同实力层次的对手,采用了不同的策略来迎战
package com.example.mode2;
public class Client3 {
public static void main(String[] args) {
Context context;
context = new Context(new WeakRivalStrategy());
context.fighting();
context = new Context(new CommonRivalStrategy());
context.fighting();
context = new Context(new StrongRivalStrategy());
context.fighting();
}
}
- 通过策略类来封装条件语句,使代码不会变得过于臃肿。
2. 策略模式的使用场景和缺点
- 使用场景
- 对客户隐藏策略算法的实现
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别。
- 在一个类中定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入到他们各自的Strategy类中,代替这些条件语句。
- 优点
- 避免多重条件语句,多重条件语句不易维护
- 易于拓展,添加策略只需要实现接口即可。
- 缺点
- 每一个策略都是一个类,复用性小。
- 上层模块必须知道有哪些策略,才可以使用这些策略,和迪米特原则违背。
6.5.2 模块方法模式
- 定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类不改变一个算法的结构即可重定义算法的某些特定步骤。
1. 模块方法的简单实现
- 模版方法就是封装固定的流程,像模版一样,第一步做什么,第二步做什么。
- 创建抽象类,定义算法框架
- 接着举武侠的例子,一个武侠要战斗的时候,有一套固定的流程。就是运行内功、开启经脉、准备武器和使用招式。
package com.example.mode2;
public abstract class AbstractSwordsman {
//该方法为final,防止算法框架被覆写
public final void fighting(){
//运行内功,抽象方法
neigong();
//调整经脉,具体方法
meridian();
if(hasWeapons()){
weapons();
}//2
//使用招式
movers();
//钩子方法
hook(); //1
}
//空实现方法
protected void hook(){}
protected abstract void neigong();
protected abstract void weapons();
protected abstract void movers();
protected void meridian(){
System.out.println("开启正经与奇功");
}
protected boolean hasWeapons(){
//是否有武器,默认有
return true;
}
}
- 具体实现类
- 张无忌没有武器,覆盖了判断是否有武器的钩子方法
package com.example.mode2;
public class ZhangWuJi extends AbstractSwordsman{
//他没有武器,所以返回false
@Override
protected void neigong() {
System.out.println("运行九阳神功");
}
@Override
protected void weapons() {
}
@Override
protected void movers() {
System.out.println("使用招式乾坤大挪移");
}
@Override
protected boolean hasWeapons() {
return false;
}
}
- 来看用武器的张三丰
package com.example.mode2;
public class ZhangSanFeng extends AbstractSwordsman{
@Override
protected void neigong() {
System.out.println("运行纯阳无极神功");
}
@Override
protected void weapons() {
System.out.println("使用真武剑");
}
@Override
protected void movers() {
System.out.println("使用招式神门十三剑");
}
@Override
protected void hook() {
System.out.println("突然肚子不舒服,老夫先去趟厕所");
}
}
- 客户端调用
package com.example.mode2;
public class Client4 {
public static void main(String[] args) {
ZhangWuJi zhangWuJi = new ZhangWuJi();
zhangWuJi.fighting();
ZhangSanFeng zhangSanFeng = new ZhangSanFeng();
zhangSanFeng.fighting();
}
}
2. 使用场景和优缺点
6.5.3 观察者模式
- 观察者模式又叫做发布-订阅模式,属于行为设计模式的一种,是在项目中经常使用的模式。
- 定义:定义对象间一种一对多的依赖关系,每当一个对象状态改变时,所有依赖于它的对象都会得到通知并被自动更新。
1. 观察者模式的简单实现
- 拿微信公众号来举例。如果微信用户是观察者,微信公众号就是被观察者。有多个微信用户关注了一个公众号,当公众号更新的时候,就会通知这些订阅的微信用户。
- 抽象观察者
- 定义了一个更新的方法
package com.example.mode2;
public interface Observer {
public void update(String message);
}
- 具体观察者
- 微信用户是具体观察者,里面实现了更新方法
package com.example.mode2;
public class WeixinUser implements Observer{
//微信用户名
private String name;
public WeixinUser(String name){
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "-" + message);
}
}
- 抽象被观察者
- 抽象被观察者,提供了attach、detach、notify方法
package com.example.mode2;
public interface Subject {
//增加订阅者
public void attach(Observer observer);
//删除订阅者
public void detach(Observer observer);
//通知订阅者更新消息
public void notify(Observer message);
}
- 具体被观察者
- 微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法
package com.example.mode2;
import java.util.ArrayList;
import java.util.List;
public class SubscriptionSubject implements Subject{
//存储订阅公众号的微信用户
private List<Observer> weixinUserList = new ArrayList<Observer>();
@Override
public void attach(Observer observer) {
weixinUserList.add(observer);
}
@Override
public void detach(Observer observer) {
weixinUserList.remove(observer);
}
@Override
public void notify(String message) {
for(Observer observer : weixinUserList){
observer.update(message);
}
}
}
- 客户端调用
package com.example.mode2;
public class Client5 {
public static void main(String[] args) {
SubscriptionSubject mSubscriptionSubject = new SubscriptionSubject();
//创建微信用户
WeixinUser user1 = new WeixinUser("1111");
WeixinUser user2 = new WeixinUser("2222");
WeixinUser user3 = new WeixinUser("3333");
//订阅公众号(订阅)
mSubscriptionSubject.attach(user1);
mSubscriptionSubject.attach(user2);
mSubscriptionSubject.attach(user3);
//公众号更新消息发送给微信用户(改变)
mSubscriptionSubject.notify("小宁的博客更新了!");
}
}