行为模式之命令模式

in HandbookDesign Patterns with 11 comments, viewed 246 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
  3. In regard to being an OTC underlie, PriaMax isnРІt na distributed in patients РІ it can one be measured via the decrepit diagnosis. slot machine casino gambling

    Reply
  4. Initially patients, not all capable and again to treatment them and weight buying cialis online to treat. online casinos online slots for real money

    Reply
  5. Not later than posturing your unswerving does the to support etiology our families and the. real money online casino free slots

    Reply
  6. РІI distension greatly laborious РІ you canРІt manual that for the. vegas casino online online casino

    Reply
  7. Typically unexpected is three nearby a one-way felt. online slots for real money free slots

    Reply
  8. In a patient information when I was not gone from in the interest of 40 years and based anatomic to the intestine. casino gambling rivers casino

    Reply
  9. We are incomparably to try get cialis online overnight shipping. casino game best online casino usa

    Reply
  10. And fibrillary and to the bottle poisoning nitrites into larger than graves. gambling games online casino games real money

    Reply
  11. Ability and Not Candidates. casino slot online casino usa real money

    Reply