23种设计模式之命令模式

命令模式是行为型设计模式之一。命令模式相对于其他的设计模式来说并没有那么多的条条框框,其实它不是一个很“规矩”的设计模式,就是因为这一点,命令模式相对于其他的设计模式更为灵活多变。

命令模式的定义
将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式的使用场景
需要抽象出待执行的动作,然后以参数的形式提供出来—类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品。
在不同的时刻指定、排序和执行请求。一个命令对象可以有与初始请求无关的生存期。
需要支持取消操作。
支持修改日志功能,这样当系统崩溃时,这些修改可以被重新做一遍。
需要支持事务操作。

UML类图
这里写图片描述
由图可以看出命令模式的通用代码:

/**
 * Created by jmfstart on 2017/6/1.
 */
//接收者类
public class Receiver {
    public void action(){
        System.out.println("接受者类执行具体操作");
    }
}

//抽象命令接口
public interface Command {
    void execute();
}

//具体命令类
public class ConcreteCommand implements Command {
    private Receiver receiver;//持有一个对接收者对象的引用

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        //调用接收者的相关方法来执行具体逻辑
        receiver.action();
    }
}

//请求者类
public class Invoker {
    private Command command; // 持有一个对相应命令对象的引用

    public Invoker(Command command) {
        this.command = command;
    }
    public void action(){
        // 调用具体命令对象的相关方法,执行具体命令
        command.execute();
    }
}

//客户端
public class Client {
    public static void main(String[] args){
        //构造一个接收者对象
        Receiver receiver = new Receiver();

        //根据接收者对象构造一个命令对象
        ConcreteCommand command = new ConcreteCommand(receiver);

        //根据具体的对象构造请求者对象
        Invoker invoker = new Invoker(command);

        // 执行请求方法
        invoker.action();
    }
}

角色介绍:
抽象命令(Command):定义命令的接口,声明执行的方法。

具体命令(ConcreteCommand):具体命令,实现要执行的方法,它通常是“虚”的实现;通常会有接收者,并调用接收者的功能来完成命令要执行的操作。

接收者(Receiver):真正执行命令的对象。任何类都可能成为一个接收者,只要能实现命令要求实现的相应功能。

调用者(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

客户端(Client):命令由客户端来创建,并设置命令的接收者。

命令模式代码的简单实现:

//命令者抽象 定义执行方法
public interface Command {
    /**
     * 执行命令的方法
     */
    void execute();
}

//具体命令者 向左、右、掉落、变换
public class LeftCommand implements Command {
    //持有一个接受者俄罗斯方块游戏对象的引用
    private TetrisMachine machine;

    public LeftCommand(TetrisMachine machine) {
        this.machine = machine;
    }

    @Override
    public void execute() {
        //调用游戏机里的具体方法执行操作
        machine.toLeft();
    }
}

//具体命令者 向左、右、掉落、变换
public class RightCommand implements Command {
    //持有一个接受者俄罗斯方块游戏对象的引用
    private TetrisMachine machine;

    public RightCommand(TetrisMachine machine) {
        this.machine = machine;
    }

    @Override
    public void execute() {
        //调用游戏机里的具体方法执行操作
        machine.toRight();
    }
}

//具体命令者 向左、右、掉落、变换
public class FallCommand implements Command {
    //持有一个接受者俄罗斯方块游戏对象的引用
    private TetrisMachine machine;

    public FallCommand(TetrisMachine machine) {
        this.machine = machine;
    }

    @Override
    public void execute() {
        //调用游戏机里的具体方法执行操作
        machine.fastToBottom();
    }
}

//具体命令者 向左、右、掉落、变换
public class TransformCommand implements Command {
    //持有一个接受者俄罗斯方块游戏对象的引用
    private TetrisMachine machine;

    public TransformCommand(TetrisMachine machine) {
        this.machine = machine;
    }

    @Override
    public void execute() {
        //调用游戏机里的具体方法执行操作
        machine.transform();
    }
}

//请求者类,命令由按钮发起
public class Buttons {
    private LeftCommand leftCommand;// 向左移动的命令对象引用
    private RightCommand rightCommand;// 向右移动的命令对引用
    private FallCommand fallCommand;// 向下加速的命令对象引用
    private TransformCommand transformCommand;// 变换形状的命令对象引用

    public void setLeftCommand(LeftCommand leftCommand) {
        this.leftCommand = leftCommand;
    }

    public void setRightCommand(RightCommand rightCommand) {
        this.rightCommand = rightCommand;
    }

    public void setFallCommand(FallCommand fallCommand) {
        this.fallCommand = fallCommand;
    }

    public void setTransformCommand(TransformCommand transformCommand) {
        this.transformCommand = transformCommand;
    }

    /**
     * 按下按钮向左移动
     */
    public void toLeft(){
        leftCommand.execute();
    }
    /**
     * 按下按钮向右移动
     */
    public void toRight(){
        rightCommand.execute();
    }

    /**
     * 按下按钮快速落下
     */
    public void fall(){
        fallCommand.execute();
    }

    /**
     * 按下按钮改变形状
     */
    public void transform(){
        transformCommand.execute();
    }
}

//客户端
public class Player {
    public static void main(String[] args){
        //首先要有俄罗斯方块游戏
        TetrisMachine machine = new TetrisMachine();

        // 根据游戏我们构造4种命令
        LeftCommand leftCommand = new LeftCommand(machine);
        RightCommand rightCommand = new RightCommand(machine);
        FallCommand fallCommand = new FallCommand(machine);
        TransformCommand transformCommand = new TransformCommand(machine);

        // 按钮可以执行不同的命令
        Buttons buttons = new Buttons();
        buttons.setLeftCommand(leftCommand);
        buttons.setRightCommand(rightCommand);
        buttons.setFallCommand(fallCommand);
        buttons.setTransformCommand(transformCommand);

        // 具体按下那个按钮玩家说了算
        buttons.toLeft();
        buttons.toRight();
        buttons.fall();
        buttons.transform();
    }
}

总结

模式分析
本质:对命令进行封装,将发出命令与执行命令的责任分开。

每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。

请求方和接收方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
使请求本身成为一个对象,这个对象和其它对象一样可以被存储和传递。

命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

优点

解除了请求者与实现者之间的耦合,降低了系统的耦合度。

对请求排队或记录请求日志,支持撤销操作。

可以容易地设计一个组合命令。

新命令可以容易地加入到系统中。

缺点

因为针对每一个命令都需要设计一个具体命令类,使用命令模式可能会导致系统有过多的具体命令类。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值