`
wuhongyu
  • 浏览: 404316 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

JAVA设计模式学习笔记6——命令模式(Command Pattern)

 
阅读更多

命令模式(Command Pattern)——将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持科撤销的操作。

    命令模式适用于“请求-响应”模式的功能,将用户的请求封装成对象(命令),用户需要执行什么样的操作,就调用什么样的命令,而无需知道命令的执行逻辑是什么。

    命令模式主要包含以下几个概念:

1、Command:所有命令的抽象类,一般需要对外公开一个执行命令的方法execute,如有需要还需提供一个命令的撤销方法undo。

2、ConcreteCommand:命令的实现类。

3、Invoker:调用者,负责命令的调度。

4、Reveiver:接收者,负责命令的接收和执行。

5、Client:客户端,命令的发起者。

 

    比如,一个有存取款功能的ATM机,它可以向某个银行的卡里存款,也可以从任何支持银联接口的银行卡里取款。不同的银行系统对存款、取款功能的实现均有不同,我们不关心银行怎么实现,只要点击ATM上的按钮就行了。这个例子中,银行的存款和取款分别为两个具体的命令实现类(ConcreteCommand);ATM机充当调用者(Invoker),负责调用银行存款或取款的命令;银行的系统为接收者(Reveiver),处理存款和取款的业务逻辑;使用ATM机的人就是客户端。

 

    首先定义一个命令的抽象类,只有两个方法,执行和撤销:

 

public interface Command {
	public void execute();
	public void undo();
}

    模拟两个银行的系统,建行(CCB)和招行(CMB),简单一点,只有存款和取款的功能。为了模拟银行系统实现的差异,将存款、取款方法取成不同的名字。

 

    建行:

 

public class Ccb {
	public void cunqian(long amount) {
		System.out.println("向建设银行存入金额:" + amount);
	}

	public void quqian(long amount) {
		System.out.println("从建设银行取出金额:" + amount);
	}
}

    招行:

public class Cmb{
	public void saveMoney(long amount) {
		System.out.println("向招商银行存入金额:" + amount);
	}
	public void getMoney(long amount) {
		System.out.println("从招商银行取出金额:" + amount);
	}
}

    将银行的存款、取款动作封装成命令对象。为了避免太复杂,存款命令的撤销就当再取出来,取款命令的撤销就再存回去。

    建行的存款命令:

 

public class CcbDepositCommand implements Command {
	private Ccb ccb = new Ccb();
	@Override
	public void execute() {
		ccb.cunqian(100);
	}
	@Override
	public void undo() {
		ccb.quqian(100);
	}
}

    建行的取款命令:

 

 

public class CcbWithdrawCommand implements Command {
	private Ccb ccb = new Ccb();
	@Override
	public void execute() {
		ccb.quqian(100);
	}
	@Override
	public void undo() {
		ccb.cunqian(100);
	}
}

    招行的存款命令:

 

 

public class CmbDepositCommand implements Command {
	private Cmb cmb = new Cmb();
	@Override
	public void execute() {
		cmb.saveMoney(100);
	}
	@Override
	public void undo() {
		cmb.getMoney(100);
	}
}

    招行的取款命令:

 

 

public class CmbWithdrawCommand implements Command {
	private Cmb cmb = new Cmb();
	@Override
	public void execute() {
		cmb.getMoney(100);
	}
	@Override
	public void undo() {
		cmb.saveMoney(100);
	}
}

    ATM机刚出厂时可能还没设置任何命令,所以为每个按钮预置一个什么都不做的命令:

public class NoCommand implements Command {
	@Override
	public void execute() { }
	@Override
	public void undo() { }
}

    现在来实现一个刚出厂的ATM机,它可能完成任何银行的存取款命令,这些命令由负责购买ATM机的银行日后自行规划:

public class Atm {
	private Command[] command;
	
	public Atm(){
		this.command = new Command[]{new NoCommand()};
	}
	//设置一组要执行的命令
	public void setCommand(Command command[]) {
		this.command = command;
	}
	//执行命令的方法
	public void action(int i) {
		this.command[i].execute();
	}
	//撤销命令的方法
	public void cancel(int i) {
		this.command[i].undo();
	}
}

  

    现在假设要实现一个建行的ATM机,只有三个功能:1是向建行存款;2是从建行取款;3从招行取款。只要为ATM设置上相应的命令就可以了。测试类:

public class Test {
	/**
	 * 命令模式——将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。
	 * 命令模式也支持科撤销的操作。
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		//调用者来执行命令
		Atm atm = new Atm();
		Command[] commands = new Command[3];
		commands[0] = new CcbDepositCommand();
		commands[1] = new CcbWithdrawCommand();
		commands[2] = new CmbWithdrawCommand();
		atm.setCommand(commands);
		atm.action(0);
		atm.cancel(0);
		atm.action(1);
		atm.cancel(1);
		atm.action(2);
		atm.cancel(2);
	}
}

    当然,如果我们不适用ATM机,直接到银行的窗口,营业员也可以直接调用系统相应的命令:

		//直接执行具体命令
		Command command = new CcbDepositCommand();
		command.execute();
		command.undo();

 

    命令模式的扩展性、封装性很好,可以很好的将用户请求与请求的实现解耦,对需求的变化也更容易扩展。但一个很简单的请求都需要封装为一个命令,也会导致类的膨胀,因此开发时需根据实际需要判断是否使用命令模式。

 

 

 

 

 

 

 

0
0
分享到:
评论
1 楼 di1984HIT 2015-02-05  
命令模式写的很好!

相关推荐

Global site tag (gtag.js) - Google Analytics