`

读《研磨设计模式》-代码笔记-命令模式-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();
		}
	}

}



0
3
分享到:
评论

相关推荐

    研磨设计模式-配套源代码

    "研磨设计模式-配套源代码"很显然是一份与学习和理解设计模式相关的资源,其中包含了实际的编程示例。这份压缩包可能包括了多种常见设计模式的实现,如单例模式、工厂模式、观察者模式、装饰器模式等,通过源代码的...

    研磨设计模式-配套源代码.7z

    《研磨设计模式》是一本深入探讨软件设计模式的书籍,其配套源代码包含了许多经典设计模式的实际应用示例。这些源代码可以帮助读者更直观地理解设计模式的原理和使用方法,进一步提升软件开发能力。 设计模式是软件...

    研磨设计模式-配套源代码.rar

    《研磨设计模式》是一本深入探讨软件设计模式的书籍,配套源代码是作者为了帮助读者更好地理解和应用书中介绍的设计模式而提供的实践示例。设计模式是软件开发中经过实践检验的、解决常见问题的模板,它为软件设计...

    研磨设计模式-配套源代码 UTF-8格式

    《研磨设计模式》是一本深入探讨软件设计原则与实践的经典书籍,其配套源代码提供了丰富的实例,帮助读者更好地理解和应用各种设计模式。这个UTF-8格式的压缩包包含了书中介绍的各种设计模式的实现,是学习和研究...

    研磨设计模式--chjavach的博客文章

    本文将深入探讨五个关键的设计模式:单例模式、工厂方法模式、策略模式、命令模式和桥接模式,这些都是Java编程中常用且至关重要的设计原则。 首先,我们来看**单例模式**。单例模式确保一个类只有一个实例,并提供...

    研磨设计模式-陈臣.epub

    “1.1 设计模式是什么 1.1.1 什么是模式 从字面上理解,模,就是模型、模板的意思;式,就是方式、方法的意思。综合起来,所谓模式就是:可以作为模型或模板的方式或方法。... “研磨设计模式”。 iBooks.

    研磨设计模式-陈臣.王斌.扫描高清版PDF

    设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;...

    研磨设计模式-陈臣pdf

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式书-配套源代码(全)

    1:本源代码是《研磨设计模式》一书的配套源代码 2:每个模式的示例源代码放在一个单独的文件夹下,以该模式的英文名称命名 3:每个模式下分成多个example,按照书的示例顺序分别命名为example1、example2.........

    研磨设计模式-陈臣.mobi kindle版

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式-part2

    第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式...

    研磨设计模式-part4

    第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式...

    研磨设计模式-part3

    第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式...

    研磨设计模式源码

    《研磨设计模式源码》是一份非常宝贵的资源,它提供了设计模式的实践代码,帮助开发者深入理解并应用这些模式。设计模式是软件工程中经过长期实践总结出来的一套通用解决方案,它们描述了在特定场景下如何解决常见...

    研磨设计模式 源代码

    《研磨设计模式》是一本深入探讨软件设计模式的经典书籍,源代码包含了书中所讲解的各种设计模式的实际应用示例。设计模式是软件工程中的重要概念,它们是经过反复验证、在特定情境下解决常见问题的有效解决方案。...

    研磨设计模式全部源代码

    这个压缩包“研磨设计模式全部源代码”包含了多种设计模式的实现,这些模式可以帮助开发者写出更可维护、可扩展和可复用的代码。下面将详细讲解其中可能包含的一些重要设计模式及其应用。 1. 工厂模式:这是最简单...

    研磨设计模式带书签完整版228M.7z.001

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式(完整带书签).part2.pdf

    第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式...

    研磨设计模式PDF

    如命令模式(Command)将请求封装为一个对象,从而使用户能够参数化不同请求,排队请求,支持撤销操作等;责任链模式(Chain of Responsibility)避免对象之间的耦合,使得多个对象有机会处理请求;解释器模式...

    研磨设计模式 演示源代码

    12. **命令模式**:将请求封装为一个对象,使得你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,也可以支持可撤销的操作。 13. **责任链模式**:使多个对象都有机会处理请求,从而避免请求的发送...

Global site tag (gtag.js) - Google Analytics