介绍
命令模式(Command Pattern)是一种行为型设计模式,用于将请求封装成一个对象,使得可以将不同的请求参数化、延迟执行或者支持撤销操作。该模式将请求发送者和请求接收者解耦,使得请求发送者不需要知道具体的请求接收者。
命令模式的核心概念是引入了一个命令对象(Command),该对象封装了特定的操作(或称为命令),并包含了操作所需的参数和方法。请求发送者(Invoker)通过调用命令对象的方法来发出请求,而不需要直接与请求接收者(Receiver)交互。
模式角色
(1) 抽象命令(Command)
定义了执行操作的接口,通常包含一个execute()方法,用于执行具体的操作。
(2) 具体命令(Concrete Command)
实现了抽象命令接口,封装了具体的操作,通常会持有一个具体的请求接收者对象,并调用其方法来执行操作。
(3) 请求接收者(Receiver)
执行具体操作的对象,具体命令对象会与请求接收者关联,并在执行时调用其方法来完成操作。
(4) 请求发送者(Invoker)
包含了命令对象,并在需要执行操作时调用命令对象的execute()方法来触发执行。
代码示例
package com.behavioral;
/**
* 以开关灯为例实现命令模式
* 使用者向灯发送命令,由灯执行具体命令
*/
public class CommandPattern {
public static void main(String[] args) {
// 请求接收者(Receiver)
Light light = new Light();
// 请求发送者(Invoker)
RemoteControl remoteControl = new RemoteControl();
// 生成具体的命令
Command lightOnCommand = new LightOnCommand(light);
//传送或设置命令
remoteControl.setCommand(lightOnCommand);
// 执行命令,最后是由具体的命令类(ConcreteCommand),即LightOnCommand执行的
// Light is on
remoteControl.pressButton();
// 关灯的执行拖成
Command lightOffCommand = new LightOffCommand(light);
remoteControl.setCommand(lightOffCommand);
remoteControl.pressButton(); // Light is off
}
}
/**
* 定义抽象命令接口(Command)
*/
interface Command {
void execute();
}
/**
* 具体的命令类(ConcreteCommand),实现抽象命令接口
*/
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
/**
* 请求接收者(Receiver)
*/
class Light {
public void turnOn() {
System.out.println("Light is on");
}
public void turnOff() {
System.out.println("Light is off");
}
}
/**
* 请求发送者(Invoker)
*/
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
应用场景
(1) 需要将请求发送者和请求接收者解耦
命令模式可以将请求封装成一个命令对象,使得发送者和接收者彼此解耦,它们不需要直接交互。这样可以提高系统的灵活性和可扩展性。
(2) 需要支持撤销操作
命令模式可以通过保存命令的历史记录,实现对命令的撤销操作。这对于需要实现撤销、恢复或回滚操作的场景非常有用。
(3) 需要支持事务处理
命令模式可以将一系列操作封装成一个事务,保证这些操作要么全部执行成功,要么全部回滚。这对于需要确保一组操作的原子性和一致性的场景非常有用。
(4) 需要支持延迟执行和异步执行
命令模式可以将命令对象存储起来,在需要执行时再进行调用。这样可以支持延迟执行和异步执行的需求。
(5) 需要支持命令的动态配置和扩展
命令模式可以通过动态配置和组合不同的命令对象,实现不同的操作组合。这样可以在运行时动态地添加、替换或组合命令,灵活地扩展系统的功能。
优缺点
(1) 命令模式的优点
- 降低系统的耦合度:命令模式通过将请求发送者和请求接收者解耦,使得二者可以独立地变化,而不会相互影响。
- 增强系统的灵活性和可扩展性:命令模式可以轻松地添加新的具体命令类,而不需要修改已有的代码。它还支持动态配置和扩展命令的组合,从而灵活地扩展系统的功能。
- 支持撤销和恢复操作:命令模式通过保存命令的历史记录,可以实现对命令的撤销和恢复操作。
- 支持事务处理:命令模式可以将一系列操作封装成一个事务,保证这些操作要么全部执行成功,要么全部回滚。
- 支持延迟执行和异步执行:可以将命令对象存储起来,在需要执行时再进行调用。
(2) 命令模式的缺点
- 可能会导致类膨胀:引入了许多具体命令类和请求接收者类,可能会增加系统的类和对象数量。
- 命令的无状态性:命令模式中的命令对象通常是无状态的,它们只负责执行特定的操作,而不维护状态。这可能需要在某些情况下引入其他的管理机制。
Android中的应用-Activity
Android中Activity的生命周期执行就是通过命令模式实现的。
其中system端作为请求者,向APP端发送命令,APP端收到命令后执行具体Activity的生命周期。
- system端进程:请求发送者(Invoker),向APP端发送ClientTransactionItem子类对象;
- ClientTransactionItem对象:抽象命令(Command),定义了生命周期对象的接口,将它封装到ClientTransaction对象中并跨进程传输给APP端;
- ResumeActivityItem等:具体命令(Concrete Command),需要由APP端执行的具体的生命周期指令;
- APP端-TransactionExecutor对象:请求接收者(Receiver),是APP端接收命令后的具体执行对象,由它调度命令的执行过程。