返回顶部
首页 > 资讯 > 前端开发 > JavaScript >详解Javascript实践中的命令模式
  • 771
分享到

详解Javascript实践中的命令模式

2024-04-02 19:04:59 771人浏览 安东尼
摘要

目录定义结构实例自定义快捷键撤销与重做录制与回放宏命令总结定义 Encapsulate a request as an object, thereby letting you par

定义

Encapsulate a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests,and support undoable operations.“

「命令模式」将「请求」封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,同时支持可撤消的操作。

这里的「请求」的定义,并不是我们前端常说的「ajax 请求」,而是一个「动作请求」,也就是发起一个行为。例如,通过遥控器关闭电视,这里的「关闭」就是一个请求。在命令模式中,我们将请求抽象成一个命令,这个命令是可复用的,它只关心它的接受者(电视);而对于动作的发起者(遥控器)来说,它只关心它所支持的命令有哪些,而不关心这些命令具体是做什么的。

结构

命令模式的类图如下:

在该类图中,我们看到五个角色:

  • Client - 创建 Concrete Command 与 Receiver(应用层)。
  • Invoker - 命令的发出者,通常会持有命令对象,可以持有很多的命令对象。
  • Receiver - 命令接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • Command - 命令接口。
  • ConcreteCommand - 命令接口的实现。

Reciver 与 Invoker 没有耦合,当需要拓展功能时,通过新增 Command,因此命令模式符合开闭原则。

实例

自定义快捷键

自定义快捷键是一个编辑器的最基本功能。通过命令模式,我们可以写出一个将键位与键位逻辑解耦的结构。


interface Command {
    exec():void
}

type Keymap = { [key:string]: Command }
class HoTKEy {
    keymap: Keymap = {}

    constructor(keymap: Keymap) {
        this.keymap = keymap
    }

    call(e: KeyboardEvent) {
        const prefix = e.ctrlKey ? 'ctrl+' : ''
        const key = prefix + e.key
        this.dispatch(key)
    }

    dispatch(key: string) {
        this.keymap[key].exec()
    }
}

class CopyCommand implements Command {
    constructor(clipboard: any) {}
    exec() {}
}

class CutCommand implements Command {
    constructor(clipboard: any) {}
    exec() {}
}

class PasteCommand implements Command {
    constructor(clipboard: any) {}
    exec() {}
}

const clipboard = { data: '' }
const keymap = {
    'ctrl+x': new CutCommand(clipboard),
    'ctrl+c': new CopyCommand(clipboard),
    'ctrl+v': new PasteCommand(clipboard)
}
const hotkey = new Hotkey(keymap)

document.onkeydown = (e) => {
    hotkey.call(e)
}

在本例中,hotkey是 Invoker,clipboard是 Receiver。当我们需要修改已有的 keymap 时,只需要新增或替换已有的key或Command即可。

是不是觉得这个写法似曾相识?没错Redux 也是应用了命令模式,Store 相当于 Receiver,Action 相当于 Command,Dispatch 相当于 Invoker。

撤销与重做

基于命令模式,我们可以很容易拓展,使它支持撤销与重做。


interface IPerson {
    moveTo(x: number, y: number): void
}

class Person implements Person {
    x = 0
    y = 0

    moveTo(x: number, y: number) {
        this.x = x
        this.y = y
    }
}

interface Command {
    exec(): void
    undo(): void
}

class MoveCommand implements Command {
    prevX = 0
    prevY = 0

    person: Person

    constructor(person: Person) {
        this.person = person
    }

    exec() {
        this.prevX = this.person.x
        this.prevY = this.person.y
        this.person.moveTo(this.prevX++, this.prevY++)
    }

    undo() {
        this.person.moveTo(this.prevX, this.prevY)
    }
}


const ezio = new Person()
const moveCommand = new MoveCommand(ezio)
moveCommand.exec()
console.log(ezio.x, ezio.y)
moveCommand.undo()
console.log(ezio.x, ezio.y)

录制与回放

想想我们在游戏中的录制与回放功能,如果将角色的每个动作都作为一个命令的话,那么在录制时就能够得到一连串的命令队列。


class Control {
    commands: Command[] = []
    
    exec(command) {
        this.commands.push(command)
        command.exec(this.person)
    }
}

const ezio = new Person()
const control = new Control()
control.exec(new MoveCommand(ezio))
control.exec(new MoveCommand(ezio))

console.log(control.commands)

当我们有了命令队列,我们又能够很容易得进行多次的撤销和重做,实现一个命令的历史记录。只需要移动当前命令队列的指针即可。


class CommandHistory {
    commands: Command[] = []
    
    index = 0
    
    get currentCommand() {
        return this.commands[index]
    }
    
    constructor(commands: Command[]) {
        this.commands = commands
    }
    
    redo() {
        this.index++
        this.currentCommand.exec()
    }
    
    undo() {
        this.currentCommand.undo()
        this.index--
    }
}

同时,如果我们将命令序列化成一个对象,它便可以用于保存与传递。这样我们将它发送到远程计算机,就能实现远程控制ezio移动的功能。


[{
    type: 'move',
    x: 1,
    y: 1,
}, {
    type: 'move',
    x: 2,
    y: 2,
}]

宏命令

对Command进行一些简单的处理就能够将已有的命令组合起来执行,将其变成一个宏命令。


class BatchedCommand implements Command {
    commands = []
    
    constructor(commands) {
        this.commands = commands
    }
    
    exec() {
        this.commands.forEach(command => command.exec())
    }
}

const batchedMoveCommand = new BatchedCommand([
    new MoveCommand(ezio),
    new SitCommand(ezio),
])

batchedMoveCommand.exec()

总结

通过以上几个例子,我们可以看出命令模式有一下几个特点:

  • 低耦合,彻底消除了接受者与调用者之间的耦合。
  • 易拓展,只需要增加新的命令便可拓展出新功能。
  • 支持序列化,易于实现保存与传递。
  • 容易导致 Command 类庞大。

以上就是详解javascript实践中的命令模式的详细内容,更多关于Javascript命令模式的资料请关注编程网其它相关文章!

--结束END--

本文标题: 详解Javascript实践中的命令模式

本文链接: https://lsjlt.com/news/125128.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解Javascript实践中的命令模式
    目录定义结构实例自定义快捷键撤销与重做录制与回放宏命令总结定义 Encapsulate a request as an object, thereby letting you par...
    99+
    2024-04-02
  • JavaScript设计模式之命令模式和状态模式详解
    目录命令模式命令模式介绍代码实现状态模式状态模式介绍代码实现小结命令模式 命令模式介绍 命令模式(Command)的定义是:用于将一个请求封装成一个对象,从而使你可用不同的请求对客户...
    99+
    2024-04-02
  • javascript设计模式的命令模式怎么实现
    这篇文章主要介绍“javascript设计模式的命令模式怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“javascript设计模式的命令模式怎么实现”文章能帮助大家解决问题。一. 认识命令模...
    99+
    2023-06-26
  • Java超详细讲解设计模式中的命令模式
    目录介绍实现个人理解:把一个类里的多个命令分离出来,每个类里放一个命令,实现解耦合,一个类只对应一个功能,在使用命令时由另一个类来统一管理所有命令。 缺点:如果功能多了就会导致创建的...
    99+
    2024-04-02
  • Java 设计模式中的命令模式详情
    目录模式介绍UML类图命令模式案例命令模式的注意事项和细节模式介绍 命令模式(Command Pattern) :在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收...
    99+
    2024-04-02
  • JavaScript设计模式之命令模式
    命令模式是JavaScript设计模式中行为型的一种设计模式; 定义:向某些对象发送请求,但是并不知道被请求的操作具体是什么,所以我们希望以一种松耦合的方式来设计程序,使得请求发送者...
    99+
    2024-04-02
  • Java设计模式之命令模式详解
    命令模式 定义:将请求封装成对象,这可以让你使用不同的请求、队列、或者日志来参数化其他对象。 何时使用命令模式?当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。 在被...
    99+
    2024-04-02
  • 详解Linux中退出编辑模式的命令
    vim 有三种模式,注意:这三种模式有很多不同的叫法,我这里是按照鸟哥的linux书中的叫法。 一般指令模式、编辑模式、指令列命令模式 1.vim 文件名      进入...
    99+
    2022-06-04
    Linux中退出编辑模式的命令 linux退出编辑
  • Java设计模式之java命令模式详解
    目录命令模式的介绍角色订单案例命令模式的优点适用场景示例代码应用宏命令----执行一组命令示例代码总结JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色...
    99+
    2024-04-02
  • 详解javascript中的Strict模式
    目录简介使用Strict modestrict mode的新特性强制抛出异常简化变量的使用简化arguments让javascript变得更加安全保留关键字和function的位置总...
    99+
    2024-04-02
  • Ansible Galaxy命令的使用实践示例详解
    目录Ansible Galaxy 初识为什么要用 ansible-galaxyansible-galaxy 命令的使用搜索 role安装 role新建 role公司的最佳实践总结An...
    99+
    2023-01-28
    Ansible Galaxy命令 Ansible Galaxy
  • JavaScript 设计模式中的代理模式详解
    前言: 代理模式,代理(proxy)是一个对象,它可以用来控制对另一个对象的访问。 现在页面上有一个香港回归最想听的金典曲目列表: <ul id="container">...
    99+
    2024-04-02
  • PHP设计模式中的命令模式
    目录命令模式(Command Pattern)是什么命令模式的优点命令模式的实现命令模式的使用总结命令模式(Command Pattern)是什么 命令模式是一种行为型模式,它将请求...
    99+
    2023-05-14
    PHP设计模式命令模式 PHP命令模式
  • JavaScript设计模式之命令模式的示例分析
    小编给大家分享一下JavaScript设计模式之命令模式的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!javascript是一种什么语言javascri...
    99+
    2023-06-14
  • Java设计模式中的命令模式怎么实现
    本文小编为大家详细介绍“Java设计模式中的命令模式怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java设计模式中的命令模式怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。个人理解:把一个类里的...
    99+
    2023-06-30
  • Python 设计模式中命令模式
    目录1.命令模式2.应用场景3.代码示例1.命令模式 命令模式的目的是解耦调用操作的对象(调用者)和提供实现的对象(接收者)。 命令模式的思路是在调用者和接收者之间插入一个命令类(C...
    99+
    2024-04-02
  • 详解Java实践之适配器模式
    目录一、前言二、适配器模式介绍三、案例场景模拟3.1、场景模拟工程3.2、场景简述3.2.1、注册开户MQ3.2.2、内部订单MQ3.2.3、第三方订单MQ3.2.4、查询用户内部下...
    99+
    2024-04-02
  • 详解Java实践之建造者模式
    目录一、前言二、开发环境三、建造者模式介绍四、案例场景模拟4.1、场景模拟工程4.2、场景简述4.2.1、物料接口4.2.2、吊顶(ceiling)4.2.3、涂料(coat)4.2...
    99+
    2024-04-02
  • Python设计模式中命令模式怎么实现
    这篇文章主要介绍了Python设计模式中命令模式怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Python设计模式中命令模式怎么实现文章都会有所收获,下面我们一起来看看吧。1.命令模式命令模式的目的是解...
    99+
    2023-06-29
  • JavaScript设计模式之中介者模式详解
    目录中介者模式现实中的中介者中介者模式的例子泡泡堂游戏为游戏增加队伍玩家增多带来的困扰用中介者模式改造泡泡堂游戏小结中介者模式 在我们生活的世界中,每个人每个物体之间都会产生一些错综...
    99+
    2022-11-13
    JavaScript 设计模式 JavaScript 中介者模式
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作