设计模式之Command模式(命令模式)

368 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

简介:

Command模式 :将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

(图画的有些许垃圾,大家勿怪😅)

生活例子类比:

  • 客人到餐厅点了一道锅包肉吃。这里的客人就是请求者,接受者就是厨师,接受到做锅包肉的命令去做这道菜。而命令类就是服务员,他不需要关心客人要吃什么,也不需要关心是哪位厨师做锅包肉,他只需要将客人的请求(要吃什么菜)记录下来,并且告知给厨师就可以了。
  • 客人与厨师之间是完全解耦的,客人告知服务员,服务员在告知厨师。
  • 而且会存在有很多客人,发起很多请求,也可能会存在客人发起请求,又突然临时有事不要这道菜了。这就是command模式可以实现的对请求排队、记录、以及支持可撤销的操作。

示例程序:

一个画图软件,用户拖动鼠标是程序会绘制出红色圆点,点击clear按钮后会清除所有圆点。(图解设计模式一书中的例子)

//Commond接口

class Command {

    execute() {

    };

}

//绘制一个点的命令,实现Command接口

class DrawCommand extends Command {

    execute() {

        console.log("draw")

    }

}

// 宏命令:一组命令集合(命令模式与组合模式的产物)

// 发布者发布一个请求,命令对象会遍历命令集合下的一系列子命令并执行,完成多任务。

class MacroCommand extends Command {

    constructor() {

        super()

        this.commands = [];

    }

    execute() {

        let cmdIterator = this.commands[Symbol.iterator]();

        let it = {

            done: false

        };

        while (!it.done) {

            it = cmdIterator.next();

            if (!it.done) {

                it.value.execute();

            }

        }

    }

    append(cmd) {

        if (cmd) {

            this.commands.push(cmd)

        }

    }

    undo() {

        if (this.commands.length) {

            this.commands.pop()

        }

    }

    clear() {

        this.commands = []

    }

}

//接受者:接受命令去执行

class DrawCanvas {

    constructor(history) {

        this.history = history

    }

    paint() {

        this.history.execute();

    }

}

//测试

let cmd1 = new DrawCommand();

let cmd2 = new DrawCommand();

let cmd3 = new DrawCommand();

//单个命令

let drawCanvas1 = new DrawCanvas(cmd1);

drawCanvas1.paint();

//宏命令

let history = new MacroCommand();

history.append(cmd1);

history.append(cmd2);

history.append(cmd3);

let drawCanvas2 = new DrawCanvas(history);

drawCanvas2.paint();

角色:

  • 命令:Command类
    
  • 具体的命令:
    
    • 画红色圆点:DrawCommand类
      
    • 清除所有圆点:MacroCommand类
      
  • 接受者:DrawCanvas类
    
  • 请求者:用户(这里是调用的时候就为请求者)
    
  • 发动者:开始执行命令的角色(这里是调用的时候也为发动者)
    

应用场景:

  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
  • 系统需要将一组操作组合在一起,即支持宏命令

优点:

  • 将调用命令的对象与和如何实现命令的对象解耦
  • command扩展性高,对请求可进行排队或日志记录。(支持撤销,队列,宏命令等功能)。

缺点

  • 额外增加命令对象太多时会使这个类膨胀得非常大