23种设计模式之命令模式

来源:互联网 发布:价格水平 知乎 编辑:程序博客网 时间:2024/06/07 01:44

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

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

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

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();    }}

总结

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

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

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

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

优点

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

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

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

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

缺点

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

原创粉丝点击