最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Javascript實(shí)踐中的命令模式

 更新時(shí)間:2021年05月04日 11:31:56   作者:淺笑·  
這篇文章主要介紹了Javascript實(shí)踐中的命令模式,對(duì)命令模式感興趣的同學(xué),可以參考下

定義

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

「命令模式」將「請(qǐng)求」封裝成對(duì)象,以便使用不同的請(qǐng)求、隊(duì)列或者日志來(lái)參數(shù)化其他對(duì)象,同時(shí)支持可撤消的操作。

這里的「請(qǐng)求」的定義,并不是我們前端常說(shuō)的「Ajax 請(qǐng)求」,而是一個(gè)「動(dòng)作請(qǐng)求」,也就是發(fā)起一個(gè)行為。例如,通過(guò)遙控器關(guān)閉電視,這里的「關(guān)閉」就是一個(gè)請(qǐng)求。在命令模式中,我們將請(qǐng)求抽象成一個(gè)命令,這個(gè)命令是可復(fù)用的,它只關(guān)心它的接受者(電視);而對(duì)于動(dòng)作的發(fā)起者(遙控器)來(lái)說(shuō),它只關(guān)心它所支持的命令有哪些,而不關(guān)心這些命令具體是做什么的。

結(jié)構(gòu)

命令模式的類圖如下:

在該類圖中,我們看到五個(gè)角色:

  • Client - 創(chuàng)建 Concrete Command 與 Receiver(應(yīng)用層)。
  • Invoker - 命令的發(fā)出者,通常會(huì)持有命令對(duì)象,可以持有很多的命令對(duì)象。
  • Receiver - 命令接收者,真正執(zhí)行命令的對(duì)象。任何類都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。
  • Command - 命令接口。
  • ConcreteCommand - 命令接口的實(shí)現(xiàn)。

Reciver 與 Invoker 沒(méi)有耦合,當(dāng)需要拓展功能時(shí),通過(guò)新增 Command,因此命令模式符合開(kāi)閉原則。

實(shí)例

自定義快捷鍵

自定義快捷鍵是一個(gè)編輯器的最基本功能。通過(guò)命令模式,我們可以寫出一個(gè)將鍵位與鍵位邏輯解耦的結(jié)構(gòu)。

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。當(dāng)我們需要修改已有的 keymap 時(shí),只需要新增或替換已有的key或Command即可。

是不是覺(jué)得這個(gè)寫法似曾相識(shí)?沒(méi)錯(cuò)Redux 也是應(yīng)用了命令模式,Store 相當(dāng)于 Receiver,Action 相當(dāng)于 Command,Dispatch 相當(dāng)于 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)

錄制與回放

想想我們?cè)谟螒蛑械匿浿婆c回放功能,如果將角色的每個(gè)動(dòng)作都作為一個(gè)命令的話,那么在錄制時(shí)就能夠得到一連串的命令隊(duì)列。

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)

當(dāng)我們有了命令隊(duì)列,我們又能夠很容易得進(jìn)行多次的撤銷和重做,實(shí)現(xiàn)一個(gè)命令的歷史記錄。只需要移動(dòng)當(dāng)前命令隊(duì)列的指針即可。

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--
    }
}

同時(shí),如果我們將命令序列化成一個(gè)對(duì)象,它便可以用于保存與傳遞。這樣我們將它發(fā)送到遠(yuǎn)程計(jì)算機(jī),就能實(shí)現(xiàn)遠(yuǎn)程控制ezio移動(dòng)的功能。

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

宏命令

對(duì)Command進(jìn)行一些簡(jiǎn)單的處理就能夠?qū)⒁延械拿罱M合起來(lái)執(zhí)行,將其變成一個(gè)宏命令。

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

總結(jié)

通過(guò)以上幾個(gè)例子,我們可以看出命令模式有一下幾個(gè)特點(diǎn):

  • 低耦合,徹底消除了接受者與調(diào)用者之間的耦合。
  • 易拓展,只需要增加新的命令便可拓展出新功能。
  • 支持序列化,易于實(shí)現(xiàn)保存與傳遞。
  • 容易導(dǎo)致 Command 類龐大。

以上就是詳解Javascript實(shí)踐中的命令模式的詳細(xì)內(nèi)容,更多關(guān)于Javascript命令模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 用javascript實(shí)現(xiàn)檢測(cè)指定目錄是否存在的方法

    用javascript實(shí)現(xiàn)檢測(cè)指定目錄是否存在的方法

    今天看到一篇關(guān)于onegreen被掛馬的代碼發(fā)現(xiàn)這個(gè)函數(shù),它用js就可以檢測(cè),制定的目錄或指定的文件是否存在,一般用來(lái)讀chm文件中的圖片來(lái)檢測(cè),目錄的存在。高手就是不學(xué)好。
    2008-01-01
  • 8個(gè)有意思的JavaScript面試題

    8個(gè)有意思的JavaScript面試題

    JavaScript 是一種有趣的語(yǔ)言,我們都喜歡它,因?yàn)樗男再|(zhì)。這篇文章主要介紹了8個(gè)有意思的JavaScript面試題 ,需要的朋友可以參考下
    2019-07-07
  • 淺析如何利用JavaScript進(jìn)行語(yǔ)音識(shí)別

    淺析如何利用JavaScript進(jìn)行語(yǔ)音識(shí)別

    所謂語(yǔ)音識(shí)別就是將你所說(shuō)的轉(zhuǎn)化成文字。Chrome 瀏覽器在版本25之后開(kāi)始對(duì)這一特性的支持。這篇文章將會(huì)詳細(xì)的介紹如何使用JavaScript進(jìn)行語(yǔ)音識(shí)別,感興趣的朋友們可以參考借鑒,下面來(lái)一起看看吧。
    2016-10-10
  • JS數(shù)組去重常用方法實(shí)例小結(jié)【4種方法】

    JS數(shù)組去重常用方法實(shí)例小結(jié)【4種方法】

    這篇文章主要介紹了JS數(shù)組去重常用方法,結(jié)合實(shí)例形式總結(jié)分析了4種常用的數(shù)據(jù)去重實(shí)現(xiàn)方法,涉及javascript數(shù)組的遍歷、判斷、追加等相關(guān)操作技巧,需要的朋友可以參考下
    2018-05-05
  • js fromCharCode輸出26個(gè)字母的代碼

    js fromCharCode輸出26個(gè)字母的代碼

    這個(gè)代碼比較簡(jiǎn)單主要是用到了fromCharCode的特性
    2008-11-11
  • 理解javascript中Map代替循環(huán)

    理解javascript中Map代替循環(huán)

    這篇文章主要幫助大家理解javascript中Map代替循環(huán),感興趣的小伙伴們可以參考一下
    2016-02-02
  • 淺談監(jiān)聽(tīng)單選框radio改變事件(和layui中單選按鈕改變事件)

    淺談監(jiān)聽(tīng)單選框radio改變事件(和layui中單選按鈕改變事件)

    今天小編就為大家分享一篇淺談監(jiān)聽(tīng)單選框radio改變事件(和layui中單選按鈕改變事件),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09
  • javascript實(shí)現(xiàn)雪花飄落效果

    javascript實(shí)現(xiàn)雪花飄落效果

    這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)雪花飄落效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • js+canvas繪制五角星的方法

    js+canvas繪制五角星的方法

    這篇文章主要介紹了js+canvas繪制五角星的方法,涉及JavaScript調(diào)用canvas組件結(jié)合數(shù)學(xué)運(yùn)算繪制圖形的相關(guān)技巧,需要的朋友可以參考下
    2016-01-01
  • javascript history對(duì)象詳解

    javascript history對(duì)象詳解

    本文主要介紹了javascript history對(duì)象的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02

最新評(píng)論

禄劝| 怀柔区| 桦南县| 河东区| 庄河市| 炉霍县| 广德县| 个旧市| 都昌县| 屏东县| 西乡县| 霍山县| 长阳| 鄂州市| 武宁县| 高要市| 扬州市| 重庆市| 新郑市| 萝北县| 中方县| 鹤庆县| 武鸣县| 遂宁市| 平山县| 连云港市| 宜章县| 灯塔市| 昌江| 丹巴县| 巩留县| 阿坝| 阳春市| 蚌埠市| 曲周县| 遵义市| 漳浦县| 宕昌县| 太仓市| 昌宁县| 靖州|