声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* GOF 在《设计模式》一书中阐述命令模式的意图:“将一个请求封装为一个对象,
* 从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。”
*/
/*
* 下面是最简单的命令模式代码示意
* 我认为是体现不出命令模式的作用:
* 本来Invoker调用Receiver,现在加了一个中间者Command,Invoker先调用Command,然后Command再调用Receiver
* 看到最后,才发现,命令模式的作用体现在“可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作”
*/
//================命令模式代码示意 begin=====================
interface ICommand {
void execute();
}
class ConcreteCommand implements ICommand {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
class Receiver {
public void action() {
System.out.println("real action.");
}
}
class Invoker {
private ICommand command;
public void setCommand(ICommand command) {
this.command = command;
}
public void runCommand() {
command.execute();
}
}
//================命令模式代码示意 end=====================
/*
* 引用书上的原话:命令模式的参数化配置,指的是:可以用不同的命令对象,去参数化配置客户的请求
* 例如下面的示例:
* 当命令对象是“开机命令”时,执行开机操作;
* 当命令对象是“关机命令”时,执行关机操作。
*/
//主板。相当于Receiver
interface IMainBoard {
void boot();
void shutdown();
}
class MainBoardImplA implements IMainBoard {
public void boot() {
System.out.println("MainBoardImplA boot.");
}
public void shutdown() {
System.out.println("MainBoardImplA shutdown.");
}
}
class BootCommand implements ICommand {
private IMainBoard mainBoardImplA;
//构造器注入
public BootCommand(IMainBoard mainboard) {
this.mainBoardImplA = mainboard;
}
public void execute() {
mainBoardImplA.boot();
}
}
class ShutdownCommand implements ICommand {
private IMainBoard mainBoardImplA;
public ShutdownCommand(IMainBoard mainboard) {
this.mainBoardImplA = mainboard;
}
public void execute() {
mainBoardImplA.shutdown();
}
}
//Invoker
class Box {
//可以做成集合的形式,放在List<ICommand>里面
private ICommand bootCommand;
private ICommand shutdownCommand;
public void setBootCommand(ICommand bootCommand) {
this.bootCommand = bootCommand;
}
public void setShutdownCommand(ICommand shutdownCommand) {
this.shutdownCommand = shutdownCommand;
}
public void bootCommandPressed() {
bootCommand.execute();
}
public void shutdownCommandPressed() {
shutdownCommand.execute();
}
}
/*
* 命令模式的“可取消的操作”
* 实现方法又分两种
* 一种是补偿法,例如操作是加法,那取消操作就执行减法
* 另一种是存储法(具体参见备忘录模式)
* 下面代码实现补偿法:
* 两个命令对象:AddOperationCommand、SubstractOperationCommand
* 这两个命令各自都有两个方法:执行和撤销
*/
interface IOperation {
int getResult();
void setResult(int result);
void add(int i);
void substract(int j);
}
//Receiver
class Operation implements IOperation {
private int result;
public void add(int i) {
result += i;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
public void substract(int j) {
result -=j;
}
}
interface IOperationCommand {
public void execute();
public void undo();
}
class AddOperationCommand implements IOperationCommand {
private IOperation operation;
private int opeNum;
public AddOperationCommand(IOperation operation, int opeNum) {
this.operation = operation;
this.opeNum = opeNum;
}
public void execute() {
operation.add(opeNum);
}
public void undo() {
operation.substract(opeNum);
}
}
class SubstractOperationCommand implements IOperationCommand {
private IOperation operation;
private int opeNum;
public SubstractOperationCommand(IOperation operation, int opeNum) {
this.operation = operation;
this.opeNum = opeNum;
}
public void execute() {
operation.substract(opeNum);
}
public void undo() {
operation.add(opeNum);
}
}
//Invoker
class Calculator {
private IOperationCommand addCommand;
private IOperationCommand substractCommand;
private List<IOperationCommand> undoCommands = new ArrayList<IOperationCommand>();
private List<IOperationCommand> redoCommands = new ArrayList<IOperationCommand>();
public void setAddCommand(IOperationCommand addCommand) {
this.addCommand = addCommand;
}
public void setSubstarctCommanc(IOperationCommand substractCommand) {
this.substractCommand = substractCommand;
}
public void add() {
addCommand.execute();
undoCommands.add(addCommand);
}
public void substract() {
substractCommand.execute();
undoCommands.add(substractCommand);
}
public void undo() {
if (undoCommands.size() > 0) {
IOperationCommand command = undoCommands.get(undoCommands.size() - 1);
command.undo();
redoCommands.add(command);
undoCommands.remove(command);
} else {
System.out.println("nothing to undo.");
}
}
public void redo() {
if (redoCommands.size() > 0) {
IOperationCommand command = redoCommands.get(redoCommands.size() - 1);
command.execute();
undoCommands.add(command);
redoCommands.remove(command);
} else {
System.out.println("nothing to redo.");
}
}
}
/*
* 命令模式的“宏命令”
* 所谓宏命令就是有一个宏命令对象,这个命令对象会触发一系列的命令对象
* 书上举了一个点菜的例子
*/
//宏命令-点菜单
class MenuCommand implements ICookCommand {
private Collection<ICookCommand> cmds = new ArrayList<ICookCommand>();
public void execute() {
for(ICookCommand cmd : cmds) {
cmd.execute();
}
}
public void addCommand(ICookCommand cmd) {
cmds.add(cmd);
}
}
//厨师,分热菜厨师和凉菜厨师-Receiver
interface ICook {
public void cook(String dishName);
}
class HotCook implements ICook {
public void cook(String dishName) {
System.out.println("热菜厨师正在做:" + dishName);
}
}
class CoolCook implements ICook {
public void cook(String dishName) {
System.out.println("凉菜厨师正在做:" + dishName);
}
}
interface ICookCommand {
public void execute();
}
//热菜-烤鸭
class KaoyaCommand implements ICookCommand {
//持有厨师对象: Command 持有 Receiver
private ICook cook;
//标准的命令模式是通过构造函数注入的,这里采用setter注入
public void setCook(ICook cook) {
this.cook = cook;
}
public void execute() {
String dishName = "烤鸭";
cook.cook(dishName);
}
}
//热菜-汤
class TangCommand implements ICookCommand {
private ICook cook;
public void setCook(ICook cook) {
this.cook = cook;
}
public void execute() {
String dishName = "汤";
cook.cook(dishName);
}
}
//凉菜-拍黄瓜
class PaihuangguaCommand implements ICookCommand {
private ICook cook;
public void setCook(ICook cook) {
this.cook = cook;
}
public void execute() {
String dishName = "拍黄瓜";
cook.cook(dishName);
}
}
//服务员 Invoker + Client
class Waiter {
private MenuCommand menuCommand = new MenuCommand();
public void orderDish(ICookCommand cmd) {
//组装-根据菜式分发给不同的厨师
ICook hotCook = new HotCook();
ICook coolCook = new CoolCook();
if (cmd instanceof KaoyaCommand) {
((KaoyaCommand)cmd).setCook(hotCook);
} else if (cmd instanceof TangCommand){
((TangCommand)cmd).setCook(hotCook);
} else if (cmd instanceof PaihuangguaCommand) {
((PaihuangguaCommand)cmd).setCook(coolCook);
}
//加入到宏命令中
menuCommand.addCommand(cmd);
}
//点菜完毕
public void orderDishFinish() {
menuCommand.execute();
}
}
/*
* 命令模式-队列请求
* 还是点菜的例子
* 核心思路就是把Command放到一个队列里面
*/
//命令队列
class CommandQueue {
private static List<ICookCommandd> cmds = new ArrayList<ICookCommandd>();
/*//书上还提到了记录日志到文件中,以便系统崩溃后能继续执行未做的菜
static {
cmds = ReadFromFile(fileName);
}
*/
//在队列里面添加服务员传过来的菜。可能会有多个服务员同时传入菜单
public synchronized static void addMenu(MenuCommandd menuCommand) {
Collection<ICookCommandd> dishCmds = menuCommand.getCommands();
for (ICookCommandd cmd : dishCmds) {
cmds.add(cmd);
}
//WriteToFile(cmds); //记录日志
}
//取出一道菜准备交给厨师去做
public synchronized static ICookCommandd getOneCommand() {
ICookCommandd cmd = null;
if (cmds.size() > 0) {
cmd = cmds.get(0);
cmds.remove(0);
//WriteToFile(cmds); //记录日志
}
return cmd;
}
}
interface ICookCommandd {
public void execute();
//设置厨师
public void setCook(ICookk cook);
//取得点菜的顾客的桌号
public int getTableNum();
}
interface ICookk {
public void cook(int tableNum, String dishName);
}
class HotCookk implements ICookk, Runnable {
private String name; //厨师姓名
public void cook(int tableNum, String dishName) {
int cookTime = (int)(20 * Math.random());
System.out.println(name + " 厨师正在为 " + tableNum + " 号桌的客人做 " + dishName);
try {
Thread.sleep(cookTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + " 厨师为 " + tableNum + " 号桌的客人做好了 " + dishName + ",耗时(毫秒):" + cookTime);
}
public void run() {
while (true) {
ICookCommandd cmd = CommandQueue.getOneCommand();
if (cmd != null) {
cmd.setCook(this);
cmd.execute();
}
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public HotCookk(String name) {
this.name = name;
}
}
class Waiterr {
private MenuCommandd menuCommand = new MenuCommandd();
public void orderDish(ICookCommandd cmd) {
menuCommand.addCommand(cmd);
}
public void orderDishFinish() {
menuCommand.execute();
}
}
class MenuCommandd implements ICookCommandd {
//记录多道菜品,也就是多个命令对象
private Collection<ICookCommandd> dishCmds = new ArrayList<ICookCommandd>();
public void execute() { //先不执行,先放入队列里排队
CommandQueue.addMenu(this);
}
public void addCommand(ICookCommandd cmd) {
dishCmds.add(cmd);
}
public Collection<ICookCommandd> getCommands() {
return dishCmds;
}
public int getTableNum() { //这个方法在这里无意义
return 0;
}
public void setCook(ICookk cook) { //这个方法在这里无意义
}
}
//简单起见,不分热菜和凉菜了
class KaoyaCommandd implements ICookCommandd {
private ICookk cook;
private int tableNum;
public void execute() {
String dishName = "烤鸭";
cook.cook(tableNum, dishName);
}
public int getTableNum() {
return tableNum;
}
public void setCook(ICookk cook) {
this.cook = cook;
}
public KaoyaCommandd(int tableNum) {
this.tableNum = tableNum;
}
}
class PaihuangguaCommandd implements ICookCommandd {
private ICookk cook;
private int tableNum;
public void execute() {
String dishName = "拍黄瓜";
cook.cook(tableNum, dishName);
}
public int getTableNum() {
return tableNum;
}
public void setCook(ICookk cook) {
this.cook = cook;
}
public PaihuangguaCommandd(int tableNum) {
this.tableNum = tableNum;
}
}
//在这个类里面启动多线程
class CookManager {
private static boolean isRunning = false; //厨师只创建一次
public static void runCookManager() {
if (!isRunning) {
HotCookk cook1 = new HotCookk("张三");
HotCookk cook2 = new HotCookk("李四");
HotCookk cook3 = new HotCookk("王五");
//启动线程
Thread t1 = new Thread(cook1);
t1.start();
Thread t2 = new Thread(cook2);
t2.start();
Thread t3 = new Thread(cook3);
t3.start();
isRunning = true;
}
}
}
//这个类是用来测试的
public class CommandPattern {
public static void main(String[] args) {
//测试-最基本的命令模式代码示意
Receiver receiver = new Receiver();
ICommand command = new ConcreteCommand(receiver); //Command拥有Receiver
Invoker invoker = new Invoker(); //Invoker拥有Command
invoker.setCommand(command);
invoker.runCommand();
//测试-命令模式的可参数化配置
//装配
Box box = new Box();
IMainBoard mainboard = new MainBoardImplA();
//开机命令对象
ICommand bootCommand = new BootCommand(mainboard);
box.setBootCommand(bootCommand);
box.bootCommandPressed();
//换成关机命令对象
ICommand shutdownCommand = new ShutdownCommand(mainboard);
box.setShutdownCommand(shutdownCommand);
box.shutdownCommandPressed();
//测试-可撤销的操作
IOperation operation = new Operation();
operation.setResult(0);
IOperationCommand addCommand = new AddOperationCommand(operation, 5);
IOperationCommand substractCommand = new SubstractOperationCommand(operation, 2);
Calculator calculator = new Calculator();
calculator.setAddCommand(addCommand);
calculator.setSubstarctCommanc(substractCommand);
calculator.add();
System.out.println("add,result = " + operation.getResult());
calculator.substract();
System.out.println("substract,result = " + operation.getResult());
calculator.undo();
System.out.println("undo,result = " + operation.getResult());
calculator.undo();
System.out.println("undo,result = " + operation.getResult());
calculator.redo();
System.out.println("redo,result = " + operation.getResult());
calculator.redo();
System.out.println("redo,result = " + operation.getResult());
//测试-宏命令
Waiter waiter = new Waiter();
ICookCommand kaoya = new KaoyaCommand();
ICookCommand tang = new TangCommand();
ICookCommand paihuanggua = new PaihuangguaCommand();
waiter.orderDish(kaoya);
waiter.orderDish(tang);
waiter.orderDish(paihuanggua);
waiter.orderDishFinish();
//测试-命令队列
CookManager.runCookManager();
//0到2号桌,每桌都点一个烤鸭和一个拍黄瓜
for (int i = 0; i < 3; i++) {
Waiterr waiterr = new Waiterr();
ICookCommandd Kaoya = new KaoyaCommandd(i);
ICookCommandd Paihuanggua = new PaihuangguaCommandd(i);
waiterr.orderDish(Kaoya);
waiterr.orderDish(Paihuanggua);
waiterr.orderDishFinish();
}
}
}