行为模式之命令模式

in HandbookDesign Patterns with 2 comments, viewed 1258 times

1 概述

命令模式(Command Pattern),是将请求封装成一系列命令对象,以解耦请求发起者和请求接收者的一种行为模式。

2 命令模式

正常情况下,请求发送者和请求接收者是相互耦合的,发送者直接调用接收者相关的方法,直接交互。
命令模式进行改造,将两者交互的媒介----命令单独抽离出来,使得发送者和接收者相互独立,只依赖于命令对象,提高了扩展性和可维护性。同时,通过命令模式,我们还能完成一些高级操作,如撤销命令方法参数化命令入队批量命令等等。

3 案例

通过一个简单的例子加深对命令模式的理解。小时候我们都玩过遥控赛车,赛车可以根据遥控器的按钮,执行相应的动作。我们作为命令的发送者,其实并不直接跟赛车交互,而是通过遥控器的指令来操作赛车:

public interface RemoteControlCar {
    void moveForward();
    void turnLeft();
    void turnRight();
    void moveBackward();
}
//请求接收者
public class RemoteControlCarImpl implements RemoteControlCar {
    @Override
    public void moveForward() {
        System.out.println("The car is moving forward!");
    }
    @Override
    public void turnLeft() {
        System.out.println("The car turns left!");
    }
    @Override
    public void turnRight() {
        System.out.println("The car turns right!");
    }
    @Override
    public void moveBackward() {
        System.out.println("The car is moving backward!");
    }
}

//命令接口,支持回退操作
public interface RemoteControlCommand {
    void execute();
    void undo();
}
public class ForwardCommand implements RemoteControlCommand {
    RemoteControlCar rcCar;
    public ForwardCommand(RemoteControlCar rcCar) {
        this.rcCar = rcCar;
    }
    @Override
    public void execute() {
        rcCar.moveForward();
    }
    @Override
    public void undo() {
        rcCar.moveBackward();
    }
}
public class BackwardCommand implements RemoteControlCommand {
    RemoteControlCar rcCar;
    public BackwardCommand(RemoteControlCar rcCar) {
        this.rcCar = rcCar;
    }
    @Override
    public void execute() {
        rcCar.moveBackward();
    }
    @Override
    public void undo() {
        rcCar.moveForward();
    }
}
public class TurnLeftCommand implements RemoteControlCommand {
    RemoteControlCar rcCar;
    public TurnLeftCommand(RemoteControlCar rcCar) {
        this.rcCar = rcCar;
    }
    @Override
    public void execute() {
        rcCar.turnLeft();
    }
    @Override
    public void undo() {
        rcCar.turnRight();
    }
}
public class TurnRightCommand implements RemoteControlCommand {
    RemoteControlCar rcCar;
    public TurnRightCommand(RemoteControlCar rcCar) {
        this.rcCar = rcCar;
    }
    @Override
    public void execute() {
        rcCar.turnRight();
    }
    @Override
    public void undo() {
        rcCar.turnLeft();
    }
}

public interface CarPlayer {
    void play();
    void undo();
    void setCommand(RemoteControlCommand command);
}
// 命令发送者,将请求委托给命令对象来完成。通过设置不同的命令,完成不同的操作
public class Kid implements CarPlayer {
    RemoteControlCommand command;
    public Kid(RemoteControlCommand command) {
        this.command = command;
    }
    @Override
    public void setCommand(RemoteControlCommand command) {
        this.command = command;
    }
    @Override
    public void play() {
        command.execute();
    }
    @Override
    public void undo() {
        command.undo();
    }
}

public class Test {
    public static void main(String[] args) {
        RemoteControlCar remoteControlCar = new RemoteControlCarImpl();
        RemoteControlCommand moveCommand = new ForwardCommand(remoteControlCar);
        RemoteControlCommand turnLeftCommand = new TurnLeftCommand(remoteControlCar);
        RemoteControlCommand turnRightCommand = new TurnRightCommand(remoteControlCar);
        RemoteControlCommand stopCommand = new BackwardCommand(remoteControlCar);

        // 需要完成不同的操作,只需设置不同的命令
        CarPlayer kid = new Kid(moveCommand);
        kid.play();
        kid.undo();
        kid.setCommand(turnLeftCommand);
        kid.play();
        kid.setCommand(turnRightCommand);
        kid.play();
        kid.setCommand(stopCommand);
        kid.play();
        kid.undo();
    }
}

输出:

The car is moving forward!
The car is moving backward!
The car turns left!
The car turns right!
The car is moving backward!
The car is moving forward!

在上述例子中,我们避免了CarPlayerRemoteControlCar的直接交互,将所有的复杂度都放在RemoteControlCommand中。对命令的增删改并不影响整体系统。在这里只演示了通过命令模式可以完成撤销操作;不过很容易联想,将几个命令放到一个命令集合中一起调用,便可以达到批量操作的目的;将命令放入队列,用类似生产者--消费者的模式,可以做到延迟命令/命令入队的要求。

JDK中我们熟悉线程,就是命令模式的运用。Runnable相当于是Thread对象的命令。

4 总结

命令对象命令模式的核心,它像是一个桥梁,连接了请求调用者和接收者,并解耦了两者的关系。它使得系统扩展变得容易。

文中例子的github地址

Responses
  1. As Effectiveness of the age-old mobility of a resigned, it has. casino games online casinos usa

    Reply
  2. Of the tubular magnesium: Concentrations j Exhaustive Analysis drawing which spokeswoman as an unsuspected and. slot games best online casino real money

    Reply