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

声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客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();
		}
	}

}



你可能感兴趣的:(java,设计模式)