"围观"设计模式(23)--行为型之命令模式(Command Pattern)

面向对象程式设计的范畴中,命令模式是一种设计模式,它尝试以物件来代表实际行动。命令物件可以把行动(action) 及其参数封装起来,于是这些行动可以被:

  • 重复多次
  • 取消(如果该物件有实作的话)
  • 取消后又再重做

这些都是现代大型应用程序所必须的功能,即“复原”及“重复”。----WIKIPEDIA


个人理解


命令模式是一个高内聚的模式,它将一个请求封装为一个对象,让你使用不同的请求将客户端参数化,在项目中应用比较广泛,他的封装性比较好,将请求方和接收方分离开来,扩展性较好。命令模式中主要有三种角色,一个是命令的接受者(Receiver),他负责对于收到的命令作出响应。一个是命令(Command)角色,他负责定义接受者需要执行什么样的命令。另一个是调用者(Invoker),接收命令调用并执行命令。但是命令模式也存在不足,如果命令较多的时候那么会存在多个子类,导致臃肿,可以结合其他的模式进行设计,如结合责任链模式实现命令的解析、结合模板方法模式减少子类的膨胀问题。


案例解析


命令模式模板


三个主要角色

1. 接收者(Receiver)

    负责具体执行哪些动作,也就是说他只负责提供一些任务的具体实现,不负责其他的部分。

2. 命令(Command)角色

    负责定义好具体的命令,包括规定好接收者需要执行的哪些动作。

3. 调用者(Invoker)角色

    负责调用命令执行,不需要知道谁是接收者,以及接收者怎么去执行,因为需要知道怎么执行的是接收者,他定义了任务的具体实现,另外不需要知道接收者是谁,这在命令角色中已经定义了哪些接收者执行哪些动作。


命令模式模板类结构图


主要代码

接收者角色:

public interface Receiver {

	public void doSomthing();
}

具体实现类

public class Receiver1 implements Receiver {

	@Override
	public void doSomthing() {
		System.out.println("Receiver1");
	}

}

命令角色

public abstract class Command {

	protected Receiver receiver;
	
	public Command(Receiver receiver) {
		this.receiver = receiver;
	}
	
	public abstract void execute();
}

具体实现类

public class Command1 extends Command {

	public Command1(Receiver receiver) {
		super(receiver);
	}

	@Override
	public void execute() {
		this.receiver.doSomthing();
	}

}

调用者角色

public class Invoker {

	private Command command;
	
	public void setCommand(Command command) {
		this.command = command;
	}
	
	public void action() {
		this.command.execute();
	}
}

测试类

public class Test {

	public static void main(String[] args) {
		// 调用者
		Invoker invoker = new Invoker();
		
		// 接收者
		Receiver receiver = new Receiver1();
		
		// 命令角色
		Command command = new Command1(receiver);
		
		invoker.setCommand(command);
		invoker.action();
	}
}


拓展案例解读

案例背景介绍

以家庭雇佣管家和保姆等佣人为例子,主要的人物有,老板、佣人,其中老板在命令模式中相当于调用者,而佣人则相当于接收者,老板对于佣人的指令相当于命令角色。那么从这一点出发来想这个案例中老板发号施令的好处所在,老板只需要说一下命令,然后,具体谁去做,怎么做老板不需要知道的,只需要等待命令的结果就行了。


案例中类结构图


主要代码

接收者角色

public interface Person {

	/**
	 * 劈柴
	 */
	public void chopping();
	
	/**
	 * 做饭
	 */
	public void makeFood();
	
	/**
	 * 喂马
	 */
	public void feedHorse();
	
	/**
	 * 周游世界
	 */
	public void travelWorld();
}

具体实现类

public class Man implements Person{

	@Override
	public void chopping() {
		System.out.println("Man --- chopping");
	}

	@Override
	public void makeFood() {
		System.out.println("Man --- makeFood");
	}

	@Override
	public void feedHorse() {
		System.out.println("Man --- feedHorse");
	}

	@Override
	public void travelWorld() {
		System.out.println("Man --- travelWorld");
	}

}
public class Woman implements Person{

	@Override
	public void chopping() {
		System.out.println("Woman --- chopping");
	}

	@Override
	public void makeFood() {
		System.out.println("Woman --- makeFood");
	}

	@Override
	public void feedHorse() {
		System.out.println("Woman --- feedHorse");
	}

	@Override
	public void travelWorld() {
		System.out.println("Woman --- travelWorld");
	}


}

命令角色

public abstract class Command {

	protected Man man = new Man();
	protected Woman woman = new Woman();
	
	public abstract void executeBossCommand();
}
具体实现类
public class ChoppingCommand extends Command {

	@Override
	public void executeBossCommand() {
		this.man.chopping();
	}
	
}
public class MakeFoodCommand extends Command {

	@Override
	public void executeBossCommand() {
		this.woman.makeFood();
	}
	
}

调用者

public class Boss {

	private Command command;

	public void setCommand(Command command) {
		this.command = command;
	}
	
	public void executeCommand(){
		this.command.executeBossCommand();
	}
}

测试类

public class MainTest {

	public static void main(String[] args) {
		Boss boss = new Boss();
		Command command1 = new ChoppingCommand();
		boss.setCommand(command1);
		boss.executeCommand();
		
		Command command2 = new MakeFoodCommand();
		boss.setCommand(command2);
		boss.executeCommand();
	}
}

模式扩展

情景介绍

假如此时老板很明确的是男的佣人要去劈柴和喂马,而女佣人可以去做饭和旅游,那么这种情况下是不是可以进行扩展呢?

主要代码

代码分析,如果说可以扩展的话,那么其余的部分需要进行变更,也就是在上面例子的基础上只需要扩展子类即可,那么这里我不再列出其类的结构图了,因为基本是一致的。

扩展命令角色为ManCommand和WomanCommand两个具体的实现类。

ManCommand

public class ManCommand extends Command{

	/**
	 * 让男人干点劈柴喂马的事
	 */
	@Override
	public void executeBossCommand() {
		this.man.chopping();
		this.man.feedHorse();
	}

}

WomanCommand

public class WomanCommand extends Command{

	/**
	 * 让女人干点做饭和周游世界的事
	 */
	@Override
	public void executeBossCommand() {
		this.woman.makeFood();
		this.woman.travelWorld();
	}

}

测试类

public class MainTest {

	public static void main(String[] args) {
		Boss boss = new Boss();
		ManCommand manCommand = new ManCommand();
		boss.setCommand(manCommand);
		boss.executeCommand();
		
		WomanCommand womanCommand = new WomanCommand();
		boss.setCommand(womanCommand);
		boss.executeCommand();
	}
}
从此案例可以看出命令模式的确扩展性很强 ,符合开闭原则。


命令模式的优点

1. 解耦:调用者和接受者之间没有关系,调用者在调用的时候,只需要执行命令(Command)中的执行方法就可以了,不需要了解哪个接收者去实际的执行。

2. 可扩展性:Command部分容易扩展,调用者不需要知道有什么改变,维持原有的设计即可完成扩展,从这点上看,符合开闭原则,对修改关闭对于扩展开放。


命令模式的缺点

命令过多的时候,会导致子类过多,系统类臃肿且难于维护,不过可以结合其他的设计模式进行整合,使得优点得到更好的发挥,如结合模板方法模式解决子类过多的问题。


命令模式的适用场景

只要可认为是命令的地方都可以采用命令模式,比如,按钮的点击和拖拽,相当于两个命令,而按钮作为接受者,此时就可以采用命令模式进行设计。


源码下载

设计模式源码下载地址


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值