前情提要
在实际开发中,我们常常会出现以下的代码情况:
if (state == 1){
haveBreakfast();
} else if (state == 2){
haveLunch();
} else if (state == 3){
haveDinner();
}
这种代码结构是不是很糟糕,如果未来又有一个新状态加入,则又要加入一个新的else if语句,如此往复,则会产生一个非常糟糕的代码结构体。
那么该如何优化这串代码呢?这里有两种方式:一种是使用责任链模式,一种是使用策略模式。
我们先来看看责任链模式是如何优化这串代码的:
责任链模式
首先上UML类图:
设计代码:
public abstract class Handler {
private Handler nextHandler;
private int state;
public Handler(int state) {
this.state = state;
}
// 处理请求传递,注意final,子类不可重写
public final void handleMessage(int state) {
// 传递状态是否符合,不符合走下一级
if (this.state == state) {
this.report();
} else {
if (this.nextHandler != null) {
// 交给下级处理
this.nextHandler.handleMessage(demand);
} else {
System.out.println("没有下级可处理");
}
}
}
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
// 抽象方法,子类实现
// 这里也用了模板方法设计模式
public abstract void report();
}
public class HaveBreakfast extends Hanlder {
public HaveBreakfast(){
super(1);
}
public void report(){
System.out.println("我在吃早餐");
}
}
public class HaveLunch extends Hanlder {
public HaveLunch(){
super(2);
}
public void report(){
System.out.println("我在吃中餐");
}
}
public class HaveDinner extends Hanlder {
public HaveDinner(){
super(3);
}
public void report(){
System.out.println("我在吃晚餐");
}
}
主类实现:
public class Client {
public static void main(String[] args) {
// 初始化
HaveBreakfast breakfast = new HaveBreakfast();
HaveLunch lunch = new HaveLunch();
HaveDinner dinner = new HaveDinner();
// 设置下一级
lunch.setNextHandler(dinner);
breakfast.setNextHandler(lunch);
// 我要吃中餐
int lunchState = 2;
breakfast.report(lunchState);
// 我要吃晚餐
int dinnerState = 3;
breakfast.report(dinnerState);
}
}
用责任链模式实现了代码的解耦,以后只要根据state值的不同,调用breakfast.report(state)即可。
策略模式
同样上UML类图:
设计代码:
public interface Strategy {
public void algorithm();
}
public class HaveBreakfast implements Strategy{
public void algorithm() {
System.out.println("我在吃早餐");
}
}
public class HaveLunch implements Strategy{
public void algorithm() {
System.out.println("我在吃中餐");
}
}
public class HaveDinner implements Strategy{
public void algorithm() {
System.out.println("我在吃晚餐");
}
}
public class Context implements Strategy{
private Strategy strategy;
private final Map<Integer, Strategy> map = new HashMap<>();
public void setStrategy(int state) {
initMap();
this.Strategy = this.map.get(state);
}
private void initMap() {
this.map.put(1, new HaveBreakfast());
this.map.put(2, new HaveLunch());
this.map.put(3, new HaveDinner());
}
public void algorithm() {
this.strategy.algorithm();
}
}
实现代码:
public class Client {
public static void main(String[] args) {
Context context = new Context();
// 我要吃中餐
int lunchState = 2;
context.setStrategy(lunchState);
context.algorithm();
// 我要吃晚餐
int dinnerState = 3;
context.setStrategy(dinnerState);
context.algorithm();
}
}
用策略模式也同样实现了代码的解耦。
策略模式 VS 责任链模式
通过以上分析,我们知道使用责任链模式和策略模式都能解耦杂乱的if-else代码,但两者又有什么不同,实际开发中我们该选用那种?结论是责任链是一种链式结构的处理方式,是有层级性的,而策略模式并没有层级关系,选用哪种可根据开发需求进行定夺。
拓展——模板方法模式
回头看看上面责任链模式的代码,Handler抽象类中定义了几个方法,一个是final修饰的handleMessage,一个是抽象方法report,还有一个是setNextHandler。这三个分别对应模板方法模式中的三个基本方法,分别是具体方法handleMessage(抽象类声明并实现,子类不实现)、抽象方法report(抽象类声明,子类必须实现)、钩子方法setNextHandler(抽象类声明并实现,子类可扩展)。
这样结合模板方法模式的好处在哪?首先加了handleMessage方法,把请求的传递判断从子类中剥离出来,让子类在report方法中专心处理请求的业务逻辑,做到了单一职责原则。子类的实现只要继承该抽象类即可,非常简单。