命令模式
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 70 课,共 87 课。
命令模式是一种行为型设计模式,它会将请求转换为一个独立的对象,其中包含有关该请求的所有信息。这样,你就可以将请求作为方法参数传递,延迟或排队执行请求,并支持可撤销的操作。
可以把它想成一家餐厅:你不直接告诉厨师要做什么菜,而是把订单写在单子上。服务员(调用者)把单子(命令)送到厨房,在那里,订单可以排队、调整优先级,甚至取消。这种模式将调用操作的对象与执行操作的对象解耦。
该模式有四个关键组成部分:声明 execute 方法的 Command 接口,实现具体操作的 ConcreteCommand 类,执行实际工作的 Receiver,以及触发命令的 Invoker:
interface Command {
void execute();
}class Light { // 接收者
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
}class RemoteControl { // 调用者
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}调用者不知道将执行什么操作。它只会调用 execute():
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // 输出:Light is ON当你需要将操作加入队列、实现撤销/重做功能或安排稍后执行任务时,命令模式特别适用。每个命令都封装了执行操作所需的一切,让你的系统更加灵活、易于扩展。
挑战
简单让我们使用命令模式来构建一个智能家居自动化系统!你将创建一个系统,通过命令控制各种家用设备,从而可以将操作排队、执行,甚至保存起来供以后使用,就像一个不需要了解每台设备内部工作原理的万能遥控器。
你将把代码组织在四个文件中:
Command.java:定义所有设备命令都将实现的Command接口。它应声明一个execute()方法,用于执行命令的操作。Devices.java:创建两个表示智能家居设备的接收者类:Television:包含powerOn()方法,该方法会输出TV is now ON;包含powerOff()方法,该方法会输出TV is now OFF;还包含setChannel(int channel)方法,该方法会输出TV channel set to [channel]。Thermostat:包含setTemperature(int temp)方法,该方法会输出Thermostat set to [temp] degrees;还包含turnOff()方法,该方法会输出Thermostat turned OFF。Commands.java:创建封装设备操作的具体命令类:TVOnCommand:在构造函数中接收一个Television,执行时调用powerOn()。TVOffCommand:在构造函数中接收一个Television,执行时调用powerOff()。TVChannelCommand:在构造函数中接收一个Television和一个int channel,执行时使用该频道调用setChannel()。ThermostatSetCommand:在构造函数中接收一个Thermostat和一个int temperature,执行时使用该温度调用setTemperature()。Main.java:创建一个RemoteControl类(调用者),其中包含setCommand(Command cmd)方法,用于存储命令;还包含pressButton()方法,用于执行存储的命令。在主方法中,你将接收两个输入:电视频道号(整数)和恒温器温度(整数)。
创建一个
Television和一个Thermostat。创建一个RemoteControl,并通过以下操作演示命令模式:- 设置一个
TVOnCommand并按下按钮 - 设置一个带有输入频道的
TVChannelCommand并按下按钮 - 设置一个带有输入温度的
ThermostatSetCommand并按下按钮 - 设置一个
TVOffCommand并按下按钮
- 设置一个
你将按顺序接收两个输入:电视频道(整数)和恒温器温度(整数)。
例如,输入为 5 和 72 时,输出为:
TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFF注意,RemoteControl 从不直接与设备交互。它只了解 Command 接口。每个命令都封装了执行其操作所需的一切,因此无需更改调用者,就能轻松添加新设备和命令!
亲手试试
import java.util.Scanner;
// TODO: 创建 RemoteControl 类(调用者),包含:
// 使用 setCommand(Command cmd) 方法存储命令
// 使用 pressButton() 方法执行存储的命令
class RemoteControl {
// TODO: 实现 RemoteControl
}
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
int channel = scanner.nextInt();
int temperature = scanner.nextInt();
// TODO: 创建一个 Television 和一个 Thermostat
// TODO: 创建一个 RemoteControl
// TODO: 演示命令模式:
// 1. 设置 TVOnCommand,然后按下按钮
// 2. 使用输入的频道设置 TVChannelCommand,然后按下按钮
// 3. 使用输入的温度设置 ThermostatSetCommand,然后按下按钮
// 4. 设置 TVOffCommand,然后按下按钮
scanner.close();
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器