读《研磨设计模式》-代码笔记-命令模式-Command

[b]声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客[url]http://chjavach.iteye.com/[/url][/b]



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();
}
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值