1 Command Pattern 命令模式
目的:将请求发送者和接收者解耦,把一个请求封装成一个对象,通过不同的请求对象来执行不同的逻辑;
实现:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
1.命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法;
2.命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开;
3.命令模式的关键在于引入了抽象命令类,请求发送者针对抽象命令类编程,只有实现了抽象命令类的具体命令才与请求接收者相关联。
2 实现
代码场景:秦昭襄王继位后,起用白起,他在咸阳发布命令,白起在东方诸国屡建战功,他们两个的协作可以看做是命令模式;
1. 秦昭襄王是调用者角色
2. 白起是接收者角色
3. 不同的命令是具体命令类角色
2.1 代码实现
抽象命令类角色:Command类
public abstract class Command {
// 执行命令
public abstract void takeOrder();
}
具体命令类角色:虎符 HuFu类
public class HuFu extends Command {
private BaiQi baiQi;
public HuFu(BaiQi baiQi) {
System.out.println("--具体命令角色--虎符--秦昭襄王將虎符交給白起");
this.baiQi = baiQi;
}
@Override
public void takeOrder() {
baiQi.fight();
}
}
具体命令类角色:自刎 Idioctonia类
public class Idioctonia extends Command {
private BaiQi baiQi;
public Idioctonia(BaiQi baiQi) {
System.out.println("--具体命令角色--自刎--秦昭襄王派使者赐剑命白起自刎");
this.baiQi = baiQi;
}
@Override
public void takeOrder() {
baiQi.ziWen();
}
}
调用者角色:秦昭襄王 QinZhaoXiang类
public class QinZhaoXiang {
private Command hufu;
public void setHufu(Command hufu) {
this.hufu = hufu;
}
//秦昭襄王
public void makeDecision() {
System.out.println("--调用者角色--秦昭襄王作出一個艰难的決定:");
hufu.takeOrder();
}
}
接收者角色:白起 BaiQi类
public class BaiQi {
private List<String> deeds = new ArrayList<String>();
private int index = 0;
public BaiQi() {
// 季君之乱
deeds.add("--未使用命令模式--秦昭襄王立,白起助魏冉平季君之乱。");
deeds.add("--接收者角色白起--秦昭襄王十四年,白起在崤函关以东灭韩魏联军二十四万人。");
deeds.add("--接收者角色白起--秦昭襄王十五年,白起夺取魏大小六十一座城池。");
deeds.add("--接收者角色白起--秦昭襄王二十八年,白起攻楚取五座城池。");
deeds.add("--接收者角色白起--秦昭襄王二十九年,白起攻陷楚都城郢,楚王避难于陈。");
}
public void fight() {
System.out.println(deeds.get(index));
index++;
}
public void ziWen() {
System.out.println("--接收者角色白起--秦昭襄王五十年,战神白起自刎于杜邮。");
}
}
2.2 涉及角色
在命令模式结构图中包含如下几个角色:
Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的 execute() 等方法,通过这些方法可以调用请求接收者的相关操作。
ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现 execute() 方法时,将调用接收者对象的相关操作(Action)。
Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的 execute() 方法,从而实现间接调用请求接收者的相关操作。
Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。
2.3 调用
调用者:
public class Client {
public static void main(String[] args) {
System.out.println("--秦武王于洛阳举鼎而死,秦昭襄王继位。");
QinZhaoXiang zhaoXiangKing = new QinZhaoXiang();
// 战神白起出现
BaiQi baiQi = new BaiQi();
// 不用命令模式的做法
baiQi.fight();
// 白起受到秦昭襄王重用
System.out.println("------------打仗的命令---------------");
Command huFu = new HuFu(baiQi);
zhaoXiangKing.setHufu(huFu);
zhaoXiangKing.makeDecision();
zhaoXiangKing.makeDecision();
zhaoXiangKing.makeDecision();
// 秦昭襄王迁怒于白起
System.out.println("------------命白起自刎的命令---------------");
Idioctonia idioctonia = new Idioctonia(baiQi);
zhaoXiangKing.setHufu(idioctonia);
zhaoXiangKing.makeDecision();
}
}
结果:
--秦武王于洛阳举鼎而死,秦昭襄王继位。
--未使用命令模式--秦昭襄王立,白起助魏冉平季君之乱。
------------打仗的命令---------------
--具体命令角色--虎符--秦昭襄王將虎符交給白起
--调用者角色--秦昭襄王作出一個艰难的決定:
--接收者角色白起--秦昭襄王十四年,白起在崤函关以东灭韩魏联军二十四万人。
--调用者角色--秦昭襄王作出一個艰难的決定:
--接收者角色白起--秦昭襄王十五年,白起夺取魏大小六十一座城池。
--调用者角色--秦昭襄王作出一個艰难的決定:
--接收者角色白起--秦昭襄王二十八年,白起攻楚取五座城池。
------------命白起自刎的命令---------------
--具体命令角色--自刎--秦昭襄王派使者赐剑命白起自刎
--调用者角色--秦昭襄王作出一個艰难的決定:
--接收者角色白起--秦昭襄王五十年,战神白起自刎于杜邮。
参考文献:
[ 1 ] 图解设计模式/(日)结城浩著;杨文轩译。–北京:人民邮电出版社,2017.1.
[ 2 ] 维基百科 设计模式
[ 3 ] 极客学院WIKI–设计模式.
[ 4 ] 菜鸟教程–设计模式.