命令模式

定义:将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化其它对象。命令模式也可以支持撤销操作。

案例一:将实现自定义接口的任务对象放进自定义执行器里面执行。

1、定义任务接口:该接口为函数式接口(JDK8新特性,接口只有一个抽象方法,可使用Lambda表达式)。

/**
 * 函数式接口
 * @author z_hh
 * @time 2018年7月27日
 */
@FunctionalInterface
public interface MyTask {

	/**
	 * 执行操作
	 */
	void execute();
}

 2、定义任务执行器。

/**
 * 自定义执行器
 * @author z_hh
 * @time 2018年7月27日
 */
public class MyExecutor {

	// 阻塞队列,当put或者take时,没有空间或没有元素时,会处于等待状态
	private BlockingQueue<MyTask> tasks;
	
	// 真正的执行器
	private ExecutorService executor;
	
	// 开关,使用volatile关键字让变量具有可见性
	private volatile boolean enable;
	
	public MyExecutor() {
		// 初始化一个100容量的有界队列
		tasks = new ArrayBlockingQueue<>(100);
	}
	
	/**
	 * 执行器启动
	 * @throws InterruptedException
	 */
	public synchronized void run() throws InterruptedException {
		// 开始时重新分配一个线程池,因为Executor被shutdown后无法再使用
		executor = Executors.newCachedThreadPool();
		enable = true;
		System.out.println("执行器开启...");
		new Thread(() -> {
			while (enable) {
				MyTask task = null;
				try {
					task = tasks.take();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 判断是否已关闭
				if (!executor.isShutdown() && Objects.nonNull(task)) {
					executor.execute(task::execute);
				}
				
			};
		}).start();
		
	}
	
	/**
	 * 增加执行任务
	 * @param task
	 * @throws InterruptedException
	 */
	public void setTask(MyTask task) throws InterruptedException {
		tasks.put(task);
	}
	
	/**
	 * 关闭执行器
	 */
	public synchronized void stop() {
		enable = false;
		executor.shutdown();
		System.out.println("执行器已关闭...");
	}
	
	/**
	 * 获取执行器是否开启的状态
	 * @return boolean false已关闭 true已开启
	 */
	public boolean getEnable() {
		return enable;
	}
	
}

3、测试代码。

public class Test {

	public static void main(String[] args) throws InterruptedException {
		
		// 创建我的执行器
		MyExecutor executor = new MyExecutor();
		
		// 添加任务1
		executor.setTask(() -> System.out.println("执行了任务1..."));
		
		sleepSecond(1);// 睡眠
		
		// 启动执行器
		executor.run();
		
		sleepSecond(1);// 睡眠
		
		// 添加任务2
		executor.setTask(() -> System.out.println("执行了任务2..."));
		
		sleepSecond(1);// 睡眠
		
		// 关闭执行器
		executor.stop();
		
		sleepSecond(1);// 睡眠
		
		// 添加任务3
		executor.setTask(() -> System.out.println("执行了任务3..."));
		
		// 启动执行器
		executor.run();
		
		sleepSecond(1);// 睡眠
		
		// 添加任务3
		executor.setTask(() -> System.out.println("执行了任务4..."));
		
	}
	
	// 睡眠指定秒数
	private static void sleepSecond(int num) {
		try {
			Thread.sleep(num * 1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

4、结果。

执行器开启...
执行了任务1...
执行了任务2...
执行器已关闭...
执行器开启...
执行了任务3...
执行了任务4...

案例二:给一个遥控器设置控制家电开关的指令(雷同《Head First设计模式(中文版)的命令模式案例》)。

1、定义指令接口,有执行和撤销的动作。

/**
 * 命令接口
 * @author z_hh
 * @time 2018年7月27日
 */
public interface Command {

	/**
	 * 执行
	 */
	void execute();
	
	/**
	 * 撤销
	 */
	void undo();
}

2、定义两个家电,电灯和电脑。

/**
 * 电灯类
 * @author z_hh
 * @time 2018年7月27日
 */
public class Light {

	public void on() {
		System.out.println("电灯打开");
	}
	
	public void off() {
		System.out.println("电灯关闭");
	}
}
/**
 * 电脑类
 * @author z_hh
 * @time 2018年7月27日
 */
public class Computer {

	public void open() {
		System.out.println("打开电脑");
	}
	
	public void close() {
		System.out.println("关闭电脑");
	}
}

3、定义实现指令接口的打开/关闭电灯和电脑的指令类。

/**
 * 打开电灯命令
 * @author z_hh
 * @time 2018年7月27日
 */
public class LightOnCommand implements Command {

	Light light;
	
	public LightOnCommand(Light light) {
		this.light = light;
	}
	
	@Override
	public void execute() {
		light.on();
	}

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

}
/**
 * 关闭电灯命令
 * @author z_hh
 * @time 2018年7月27日
 */
public class LightOffCommand implements Command {

	Light light;
	
	public LightOffCommand(Light light) {
		this.light = light;
	}
	
	@Override
	public void execute() {
		light.off();
	}

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

}
/**
 * 打开电脑命令
 * @author z_hh
 * @time 2018年7月27日
 */
public class ComputerOpenCommand implements Command {

	Computer computer;
	
	public ComputerOpenCommand(Computer computer) {
		this.computer = computer;
	}
	
	@Override
	public void execute() {
		computer.open();

	}

	@Override
	public void undo() {
		computer.close();
	}

}
/**
 * 关闭电脑命令
 * @author z_hh
 * @time 2018年7月27日
 */
public class ComputerCloseCommand implements Command {

	Computer computer;
	
	public ComputerCloseCommand(Computer computer) {
		this.computer = computer;
	}
	
	@Override
	public void execute() {
		computer.close();

	}

	@Override
	public void undo() {
		computer.open();
	}

}

4、定义什么都不做的空指令。

/**
 * 不做任何操作的命令
 * @author z_hh
 * @time 2018年7月27日
 */
public class NoCommand implements Command {

	@Override
	public void execute() {}

	@Override
	public void undo() {}

}

 

5、定义遥控器类。

/**
 * 遥控器
 * @author z_hh
 * @time 2018年7月27日
 */
public class RemoteControl {
	
	// 打开类命令
	private Command[] onCommands;
	// 关闭类命令
	private Command[] offCommands;
	// 撤销命令
	private Command undoCommand;
	
	// 构造器,初始化命令数组,并设置原始命令
	public RemoteControl() {
		onCommands = new Command[2];
		offCommands = new Command[2];
		
		Command noCommand = new NoCommand();
		
		for (int i = 0; i < 2; i++) {
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
		undoCommand = noCommand;
	}
	
	/**
	 * 设置命令
	 * @param slot
	 * @param onCommand
	 * @param offCommand
	 */
	public void setCommand(int slot, Command onCommand, Command offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}
	
	/**
	 * 打开按钮
	 * @param slot
	 */
	public void onButtonWasPushed(int slot) {
		onCommands[slot].execute();
		undoCommand = onCommands[slot];
	}
	
	/**
	 * 关闭按钮
	 * @param slot
	 */
	public void offButtonWasPushed(int slot) {
		offCommands[slot].execute();
		undoCommand = offCommands[slot];
	}
	
	/**
	 * 撤销按钮
	 */
	public void undoButtonWasPushed() {
		undoCommand.undo();
	}

}

6、测试。

/**
 * 命令模式
 * @author z_hh
 * @time 2018年7月27日
 */
public class Test {

	public static void main(String[] args) {
		
		// 创建遥控器
		RemoteControl remoteControl = new RemoteControl();
		
		// 创建电灯对象,并设置遥控器的1号开关
		Light light = new Light();
		LightOnCommand lightOnCommand = new LightOnCommand(light);
		LightOffCommand lightOffCommand = new LightOffCommand(light);
		remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
		
		// 创建电脑对象,并设置遥控器的2号开关
		Computer computer = new Computer();
		ComputerOpenCommand computerOpenCommand = new ComputerOpenCommand(computer);
		ComputerCloseCommand computerCloseCommand = new ComputerCloseCommand(computer);
		remoteControl.setCommand(1, computerOpenCommand, computerCloseCommand);
		
		// 第一组开关
		remoteControl.onButtonWasPushed(0);
		remoteControl.offButtonWasPushed(0);
		
		// 第二组开关
		remoteControl.onButtonWasPushed(1);
		remoteControl.offButtonWasPushed(1);
		
		// 回退
		remoteControl.undoButtonWasPushed();

	}

}

7、结果。

电灯打开
电灯关闭
打开电脑
关闭电脑
打开电脑

8、还可以定义宏命令:将多个指令组成一个命令,比如将打开电灯和打开电脑的指令放在一个遥控器命令上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值