目录
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
在面向对象编程当中,一个很重要的事情是设计能够使得代码松耦合。举个例子,我们需要开发一个复杂的程序,用来绘制诸如点、线、线段、圆、矩形等许多图形。
为了让代码能够实现所有种类的形状,我们需要实现很多操作来处理菜单操作。
为了让程序可维护,我们需要创建一个统一的方法来定义所有的命令,这样做便能够将所有实现细节隐藏在程序之中(这个程序实际上就是客户端)。
命令模式能够做到:
注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式。
图 1-1
上面的类图中包括以下元素:
Command(命令类):这是表示命令封装的抽象类。它声明了执行的抽象方法,该方法应该由所有具体命令实现。
ConcreteCommand(具体命令类):这是命令的实际实现。它必须执行命令并处理与每个具体命令相关的参数。它将命令委托给接收者。
Receiver(接收者):这是负责执行与命令关联的操作的类。
Invoker(调用者):这是触发命令的类。通常是外部事件,例如用户操作。
Client(客户端):这是实例化具体命令对象及其接收者的实际类。
我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。具体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。创建作为调用对象的类 Broker(触发命令的类),它接受订单并能下订单。
Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。CommandPatternDemo 类使用 Broker 类来演示命令模式。
1)先创建作为命令的接口 Order.java
Order.java
package com.zhaoyanfei.designpattern.commandpattern;
/**
* @Date 2022年10月6日
* @author zhaoYanFei
* 订单接口(Command(命令类))
*
*/
public interface Order {
void execute();
}
2)创建一个请求类 Stock.java
Stock.java
package com.zhaoyanfei.designpattern.commandpattern;
/**
* Stock 请求类
* @Date 2022年10月6日
* @author zhaoYanFei
*/
public class Stock {
private String name = "笔记本";
private int quantity = 3;
public void buy(){
System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold");
}
}
3)创建实现了 Order 接口的具体命令类
BuyStock.java
package com.zhaoyanfei.designpattern.commandpattern;
/**
* BuyStock 具体执行命令的类
* @Date 2022年10月6日
* @author zhaoYanFei
*/
public class BuyStock implements Order {
private Stock stock;
@Override
public void execute() {
// TODO Auto-generated method stub
stock.buy();
}
public BuyStock(Stock stock){
this.stock = stock;
}
}
SellStock.java
package com.zhaoyanfei.designpattern.commandpattern;
/**
* SellStock 具体执行命令的类
* @Date 2022年10月6日
* @author zhaoYanFei
*/
public class SellStock implements Order {
private Stock stock;
@Override
public void execute() {
// TODO Auto-generated method stub
stock.sell();
}
public SellStock(Stock stock){
this.stock = stock;
}
}
4)创建命令调用类 Broker.java ,将命令存放在任务队列中。
Broker.java
package com.zhaoyanfei.designpattern.commandpattern;
import java.util.ArrayList;
import java.util.List;
/**
* Broker 命令调用类
* @Date 2022年10月6日
* @author zhaoYanFei
*
*/
public class Broker {
private List<Order> orderList = new ArrayList<Order>();
//添加命令到队列中
public void addCommand(Order order) {
orderList.add(order);
}
//执行命令集合
public void executeCommand() {
for (Order order : orderList) {
order.execute();
}
//清空任务队列
orderList.clear();
}
}
5)创建客户端调用测试类 CommandPatternDemo.java
使用 Broker 类来接受并执行命令。
CommandPatternDemo.java
package com.zhaoyanfei.designpattern.commandpattern;
/**
* CommandPatternDemo 客户端调用测试类
* @Date 2022年10月6日
* @author zhaoYanFei
*
*/
public class CommandPatternDemo {
public static void main(String[] args) {
Stock stock = new Stock();
BuyStock buyStock = new BuyStock(stock);
SellStock sellStock = new SellStock(stock);
Broker broker = new Broker();
broker.addCommand(buyStock);
broker.addCommand(sellStock);
broker.executeCommand();
}
}
执行结果如下:
Undo/Redo operation(撤销 / 重做操作):命令模式允许我们将命令对象存储在队列中。这样就可以实现撤销和重做操作。
Composite command (组合命令) :复杂命令可以使用组合模式由简单命令组成,并按顺序运行。通过这种方式,我们可以以面向对象的方式构建宏。
The asynchronous method invocation(异步方法调用):命令模式用于多线程应用程序。命令对象可以在后台以单独的线程执行。java.lang.Runnable 是一个命令接口。
下面代码中,Runnable 接口充当命令接口,由 RunnableThread 具体实现执行命令
package com.zhaoyanfei.designpattern.commandpattern;
public class RunnableThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("the command implementation code");
}
}
客户端调用命令启动新线程:
package com.zhaoyanfei.designpattern.commandpattern;
public class ClientThread {
public static void main(String[] args) {
RunnableThread runnableThread = new RunnableThread();
Thread thread = new Thread(runnableThread);
thread.start();
}
}
执行程序,输出结果如下:
1、降低了系统耦合度。
2、新的命令可以很容易添加到系统中去。
使用命令模式可能会导致某些系统有过多的具体命令类。
回顾一下,这篇文章的内容
命令模式中的4个角色:
将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
下一节,我会分享行为型模式中的解释器模式。