是什么?
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
为什么用他?
在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。
一、角色
- received 真正的命令执行对象
- Command 抽象命令类
- invoker 使用命令对象的入口
- client 客户端
- concreteCommand 具体实现命令类
二、命令模式如何实现解耦?
Invoker同样是针对接口编程,不过这个接口并不是由Receiver实现,而是由命令对象实现。Invoker只管调用命令对象的execute方法即可,它根本不知道execute方法里发生了什么。命令对象就是Invoker和Receiver之间沟通的桥梁。利用命令对象,我们可以根据需要使Invoker调用某个类的某个方法等。
三、代码
package com.godliang.design.command;
import com.sun.org.apache.xpath.internal.operations.Or;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* @author GodLiang
* @version 1.0
* @date 2021/2/9 19:34
* @description: TODO 命令模式
*/
public class CommandPatternDemo {
public static void main(String[] args) {
//创建请求类股票
Stock abcStock = new Stock();
//创建命令购买股票
BuyStock buyStockOrder = new BuyStock(abcStock);
//创建命令卖出股票
SellStock sellStockOrder = new SellStock(abcStock);
//执行器
Broker broker = new Broker();
//添加命令执行器
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
//批量执行
broker.placeOrders();
broker.undoOrders();
}
}
/**
* 请求类
*/
class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold");
}
}
/**
* 命令接口
*/
interface Order {
/**
* 执行命令
*/
void execute();
/**
* 撤回
*/
void undo();
}
/**
* 实体命令类
* 购买股票
*/
class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
@Override
public void execute() {
abcStock.buy();
}
@Override
public void undo() {
abcStock.sell();
}
}
/**
* 实体命令类
* 卖出股票
*/
class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
@Override
public void execute() {
abcStock.sell();
}
@Override
public void undo() {
abcStock.buy();
}
}
/**
* 命令执行类
*/
class Broker {
/**
* 执行集合
*/
private List<Order> orderList = new ArrayList<Order>();
/**
* 撤回按先进后出的方式撤回
* @param order
*/
private Stack<Order> orderStack = new Stack<>();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
//执行完后入栈
orderStack.add(order);
}
}
/**
* 撤回
*/
public void undoOrders(){
do {
Order order = orderStack.pop();
order.undo();
}while (!orderStack.empty());
}
}
四、优缺点
优点:
- 降低了系统耦合度。
- 新的命令可以很容易添加到系统中去。
- 可以比较容易的设置组合一套命令
- 可以对命令的撤销或重置
缺点:
- 由于每个小的命令都要重新实现一个命令实现类。会导致类过多。会影响阅读与使用