命令模式是一种行为型模式。请求以命令的形式包裹在对象中,并传递给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
简单而言,就是调用者->命令->执行者,将调用者和执行者解耦。
命令模式主要定义了三种角色:
在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
需要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,使用命令模式将一组行为/命令抽象为对象,可以实现二者之间的松耦合。典型的如Hystrix断路器。
长官对士兵下达命令,长官喊“向左转!”,士兵向左转,长官喊“向右转!”,士兵就向右转。长官也可以把要下达的命令列在命令清单上,士兵接到清单,按照清单上的命令执行。
/**
* @author xujian
* 2020-12-01 14:48
*
* 军官
*
* 军官和士兵紧耦合
**/
public class General {
/**
* 士兵
*/
private Soldier soldier;
public General(Soldier soldier) {
this.soldier = soldier;
}
/**
* 下达命令
* @param order
*/
public void makeOrder(String order) {
if ("turnLeft".equals(order)) {
soldier.turnLeft();
} else if ("turnRight".equals(order)) {
soldier.turnRight();
}
}
public static void main(String[] args) {
General general = new General(new Soldier());
//下达向左转的命令
general.makeOrder("turnLeft");
//下达向右转的命令
general.makeOrder("turnRight");
}
}
该实现的缺点显而易见:军官和士兵紧耦合。如果想要增加一种命令,那么必须要修改General
类,为其加上一种if
分支。
命令接口:
/**
* @author xujian
* 2020-11-30 17:05
*
* 命令接口
**/
public interface Order {
/**
* 执行方法
*/
void execute();
}
具体的命令:
/**
* @author xujian
* 2020-11-30 17:12
*
* 向左转命令
**/
public class TurnLeftOrder implements Order {
/**
* 士兵
*/
private Soldier soldier;
public TurnLeftOrder(Soldier soldier) {
this.soldier = soldier;
}
/**
* 执行方法
*/
@Override
public void execute() {
soldier.turnLeft();
}
}
/**
* @author xujian
* 2020-11-30 17:08
*
* 向右转命令
**/
public class TurnRightOrder implements Order{
/**
* 士兵
*/
private Soldier soldier;
public TurnRightOrder(Soldier soldier) {
this.soldier = soldier;
}
/**
* 执行方法
*/
@Override
public void execute() {
soldier.turnRight();
}
}
命令执行者-士兵:
/**
* @author xujian
* 2020-11-30 17:09
*
* 士兵
**/
public class Soldier {
public void turnRight() {
System.out.println("士兵向右转!");
}
public void turnLeft() {
System.out.println("士兵向左转!");
}
}
也可以将“士兵”抽象成接口,实现多个不同类型的“士兵”实现。
命令发起者-军官:
/**
* @author xujian
* 2020-11-30 17:18
*
* 军官
**/
public class General {
/**
* 命令清单
*/
private List<Order> orderList = new ArrayList<>();
/**
* 添加命令到命令清单
* @param order
*/
public void addOrder(Order order) {
orderList.add(order);
}
/**
* 下达命令清单上的所有命令
*/
public void issueOrderList() {
for (Order order : orderList) {
issueOrder(order);
}
}
/**
* 下达命令
* @param order
*/
public void issueOrder(Order order) {
order.execute();
}
}
测试:
/**
* @author xujian
* 2020-11-30 17:26
**/
public class TestCommandMode {
public static void main(String[] args) {
General general = new General();
Soldier soldier = new Soldier();
Order orderLeft = new TurnLeftOrder(soldier);
Order orderRight = new TurnRightOrder(soldier);
general.addOrder(orderLeft);
general.addOrder(orderRight);
//执行命令清单上的命令
System.out.println("----执行命令清单上的命令----");
general.issueOrderList();
//执行指定命令
System.out.println("----执行指定命令----");
general.issueOrder(orderLeft);
}
}
执行结果:
----执行命令清单上的命令----
士兵向左转!
士兵向右转!
----执行指定命令----
士兵向左转!
从上面示例看,命令模式的实现方式取代了普通实现方式的if-else
,之前说的策略模式也是取代了普通实现方式的if-else
,并且他们的类图也很相似。那么他们有什么异同呢?
通过命令模式,降低了系统的耦合度,可以很容易扩展新的命令。但是和很多设计模式一样,可能会导致系统有过多的具体实现类。