【设计模式】命令模式

命令模式

一 概述

什么是命令模式
  • 概念:将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销操作
  • 举个例子:我们老早以前的电视和电灯都需要亲自过去开或者关,但是到了现在,我们所有的灯与电视都可以通过一个遥控器进行控制。这样我们只需要知道遥控器上的哪些按钮控制什么,点下发出相关的命令即可,而不需要直接去操作那个电器。

二 模式的结构与实现

结构
  • 接收者:接收者是一个类的实例,该实例负责执行与请求相关的操作
  • 命令接口:命令是一个接口,规定了用来封装“请求”的若干个方法
  • 具体命令:实现命令接口的类的实例
  • 请求者:包含了命令接口的实例,可以通过调用具体的命令去执行封装了请求的方法
实现

我们就按遥控器的例子来设计,假设我们有一个10个按钮的遥控器,两个控制灯的开关,两个控制电视的开关,剩下的留作未来产品的按钮,现在点上去没有效果,除了这四个按钮,还有一个特殊的撤销按钮,用来撤销上一步的操作。
具体实现:

  • 接收者
    1.电视
public class TV {
	
	public void setOn(){
		System.out.println("电视开");
	}
	
	public void setOff(){
		System.out.println("电视关");
	}
}

2.电灯

public class Light {
	
	public void setOn(){
		System.out.println("灯开了");
	}
	
	public void setOff(){
		System.out.println("灯关了");
	}

}

  • 命令接口
public interface ICommand {
	//分装请求的方法
	public void execute();
	//撤销操作
	public void undo();
}

  • 具体命令
    1.电灯开的命令
public class LightOnCommand implements ICommand{
	private Light light;
	
	public LightOnCommand(Light light) {
		this.light = light;
	}
	@Override
	public void execute() {
		light.setOn();
	}

	@Override
	public void undo() {
		light.setOff();
	}

}

2.电灯关的命令

public class LightOffCommand implements ICommand{
	private Light light;
	
	public LightOffCommand(Light light){
		this.light = light;
	}
	
	@Override
	public void execute() {
		light.setOff();
	}

	@Override
	public void undo() {
		light.setOn();
	}
}

3.电视开的命令

public class TVOnCommand implements ICommand{
	private TV tv;
	public TVOnCommand(TV tv) {
		this.tv = tv;
	}
	@Override
	public void execute() {
		tv.setOn();
	}

	@Override
	public void undo() {
		tv.setOff();
	}

}

4.电视关的命令

public class TVOffCommand implements ICommand{
	private TV tv;
	public TVOffCommand(TV tv) {
		this.tv = tv;
	}
	@Override
	public void execute() {
		tv.setOff();
	}

	@Override
	public void undo() {
		tv.setOn();
	}

}

5.空命令,用来初始化每个遥控器的按钮

public class NoCommand implements ICommand{

	@Override
	public void execute() {
		
	}

	@Override
	public void undo() {
		
	}

}
  • 请求者
public class Control {
	
	private ICommand[] onCommand;
	private ICommand[] offCommand;
	//用栈来存放操作,用来实现撤销的操作
	private Stack<ICommand> s = new Stack<>();
	
	public Control(){
		onCommand = new ICommand[5];
		offCommand = new ICommand[5];
		//初始化每个按钮
		for(int i = 0;i<onCommand.length;i++){
			onCommand[i] = new NoCommand();
		}
		for(int i = 0;i<offCommand.length;i++){
			offCommand[i] = new NoCommand();
		}
	}
	//设置按钮
	public void setOnCommand(int i,ICommand on){
		onCommand[i] = on;
		
	}
	public void setOffCommand(int i,ICommand off){
		offCommand[i] = off;
	}
	//按下开的按钮
	public void onButton(int i){
		onCommand[i].execute();
		s.push(onCommand[i]);
	}
	//按下关的按钮
	public void offButton(int i){
		offCommand[i].execute();
		s.push(offCommand[i]);
	}
	//撤销按钮
	public void undoButton(){
		s.pop().undo();
	}
}

  • 主函数
public class MainClass {
	public static void main(String[] args) {
		
		Light l = new Light();
		TV t = new TV();
		//设置遥控器
		Control c = new Control();
		ICommand lon = new LightOnCommand(l);
		ICommand lof = new LightOffCommand(l);
		ICommand ton = new TVOnCommand(t);
		ICommand tof = new TVOffCommand(t);
		
		
		c.setOnCommand(0, lon);
		c.setOnCommand(1, ton);
		
		
		c.setOffCommand(0, lof);
		c.setOffCommand(1, tof);
		
		
		//操作遥控器
		
		c.onButton(0);
		c.onButton(1);
	
		c.offButton(0);
		c.offButton(1);
		//撤销操作
		c.undoButton();
		c.undoButton();
		

	}
}

结果
在这里插入图片描述

关于宏命令(组合命令模式)

上面我们讲了普通命令模式,我们再说说宏命令也就是组合命令,顾名思义,组合命令就是将命令组合起来。其实宏命令也是一个具体的命令,只不过它包含了要组合的命令的引用,当他执行操作时,其他命令也会执行操作,所以执行一个宏命令相当于执行了很多其他命令。
具体实现
在上面的基础是我们再加一个特殊的命令宏命令,这里,我是按照开和关来组合的
1.一次全开

public class AllOnCommand implements ICommand{
	private ArrayList<ICommand> all;
	
	public AllOnCommand(ArrayList<ICommand> all){
		this.all = all;
	} 
	
	@Override
	public void execute() {
		for(int i = 0;i<all.size();i++){
			ICommand c = all.get(i);
			c.execute();
		}
	}

	@Override
	public void undo() {
		for(int i = 0;i<all.size();i++){
			ICommand c = all.get(i);
			c.undo();
		}
	}

}

2.一次全关

public class AllOffCommand implements ICommand{
	private ArrayList<ICommand> all;
	
	public AllOffCommand(ArrayList<ICommand> all){
		this.all = all;
	} 
	
	@Override
	public void execute() {
		for(int i = 0;i<all.size();i++){
			ICommand c = all.get(i);
			c.execute();
		}
	}

	@Override
	public void undo() {
		for(int i = 0;i<all.size();i++){
			ICommand c = all.get(i);
			c.undo();
		}
	}
}

主函数,在上面主函数的基础上加入

		ArrayList<ICommand> allon = new ArrayList<>();
		allon.add(lon);
		allon.add(ton);
		ICommand aon = new AllOffCommand(allon);
		ArrayList<ICommand> allff = new ArrayList<>();
		allff.add(lof);
		allff.add(tof);
		ICommand aof = new AllOffCommand(allff);
		
		c.setOnCommand(2, aon);
		c.setOffCommand(2, aof);
		
		c.onButton(2);
		c.offButton(2);

结果
在这里插入图片描述

三 模式的优点与适用场景

优点
  • 在命令模式中,请求者不与接收者交互,消除了之间的耦合
  • 在增加新命令与该命令的接收者时,不需要修改调用者的代码,调用者就可以使用新的命令,而且增加新的调用者也不用修改接收者与具体命令。
适用场景
  • 程序需要在不同的时刻指定,执行请求
  • 程序需要提供撤销操作
  • 程序需要支持宏操作

这就是我所理解的命令模式,如果我有什么错误或者你有更好的想法请告诉我。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值