欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS設(shè)計(jì)模式之命令模式的用法詳解

 更新時(shí)間:2023年08月27日 10:07:50   作者:慕仲卿  
JavaScript中的命令模式是一種設(shè)計(jì)模式,它提供了一種將命令封裝為對(duì)象的方式,從而允許我們將請(qǐng)求與實(shí)際執(zhí)行該請(qǐng)求的操作對(duì)象解耦,這種模式可以在不同的場景中使用,例如實(shí)現(xiàn)撤銷/重做操作、隊(duì)列任務(wù)等,本文我們將講解命令設(shè)計(jì)模式在JS中的使用

相關(guān)定義:

  • 使用命令模式,可以將【請(qǐng)求的調(diào)用者】和【請(qǐng)求的執(zhí)行者】解耦。

  • 調(diào)用者通過【持有命令對(duì)象】來【間接調(diào)用】接收者的方法,而無需【直接引用】接收者或了解其【具體實(shí)現(xiàn)】。

  • 這種解耦使得我們能夠更加靈活地【擴(kuò)展】和【改變】命令的調(diào)用方式。

  • 例如,我們可以【將命令對(duì)象保存在【隊(duì)列中】】,實(shí)現(xiàn)命令的【排隊(duì)】和【異步執(zhí)行】。

  • 還可以記錄命令的【歷史,以支持撤銷和重做】操作。

  • 命令模式應(yīng)用場景,【菜單操作】、【多級(jí)撤銷】、【批處理任務(wù)】等。

自我理解:

  • 執(zhí)行者對(duì)象E:普通對(duì)象,提供了整個(gè)流程中的執(zhí)行方法,此方法對(duì)于具體的命令是可感知的,對(duì)于調(diào)用者是無感知的!

  • 抽象命令類A:規(guī)定了具體命令的基本結(jié)構(gòu),為調(diào)用者提供統(tǒng)一的調(diào)用接口。

  • 具體命令類S:是對(duì)抽象命令類的實(shí)現(xiàn),核心是封裝了執(zhí)行者,準(zhǔn)確來說命令只封裝了執(zhí)行者的部分方法;抽象方法的執(zhí)行本質(zhì)上是執(zhí)行了這些方法。

  • 調(diào)用者對(duì)象C:封裝了兩個(gè)方法和一個(gè)屬性;屬性表示的是當(dāng)前命令,第一個(gè)方法是設(shè)置/切換命令具體值,第二個(gè)方法是執(zhí)行此方法。

  • S封裝了E,C只能接觸到S,所以C和E是解耦的

  • A和S的關(guān)系是一對(duì)多

解耦體現(xiàn):

  • C無需了解S具體內(nèi)容,只需完成觸發(fā) ;

  • S無需知道E怎么完成任務(wù),只需調(diào)用E暴露出來的方法即可;

  • S和E之間是多對(duì)多的關(guān)系,即一個(gè)S可以由多個(gè)E的部分方法組合完成,一個(gè)E也可以被不同的S封裝其上不同的部分方法;

  • C維護(hù)的不只是一個(gè)S,還可以是一個(gè)S隊(duì)列,當(dāng)觸發(fā)到來的時(shí)候,S隊(duì)列依次執(zhí)行。

代碼舉例1:

// 接收者對(duì)象
class Light {
? ? turnOn() {}
? ? turnOff() {}
}
// 命令接口
abstract class Command {
? ? abstract execute():void;
}
// 具體命令:打開燈
class TurnOnCommand extends Command {
? ? constructor(public light: Light) { super() }
? ? execute() { this.light.turnOn() }
}
// 具體命令:關(guān)閉燈
class TurnOffCommand extends Command {
? ? constructor(public light: Light) { super() }
? ? execute() { this.light.turnOff() }
}
// 調(diào)用者對(duì)象
class RemoteControl {
? ? command: Command;
? ? setCommand(command: Command) { this.command = command }
? ? pressButton() { this.command.execute() }
}
// 使用示例
// 創(chuàng)建執(zhí)行者
const light = new Light();
// 創(chuàng)建具體命令對(duì)象,封裝執(zhí)行者
const turnOnCommand = new TurnOnCommand(light);
const turnOffCommand = new TurnOffCommand(light);
// 創(chuàng)建調(diào)用者對(duì)象
const remoteControl = new RemoteControl();
// 設(shè)置具體命令對(duì)象然后執(zhí)行
remoteControl.setCommand(turnOnCommand);
remoteControl.pressButton();

代碼舉例2:

使用命令設(shè)計(jì)模式可以靈活組合網(wǎng)絡(luò)請(qǐng)求,如下所示:

// 請(qǐng)求接收者
class Reciever {
? async get(path: string) {
? ? const res = await fetch(`https://rec.example.com/${path}`);
? ? const data = await res.json();
? }
}
// 命令接口
class Cmd { exe() {} }
// 具體命令:發(fā)送請(qǐng)求
class RCd extends Cmd {
? constructor(public rec, public url) {
? ? super();
? }
? exe() {
? ? return this.rec.get(this.url);
? }
}
// 調(diào)用者對(duì)象
class RM {
? cQueue: Cmd[] = [];
? add(command: Cmd) {
? ? this.cQueue.push(command);
? }
? pReq() {
? ? const promises = this.cQueue.map((command) => command.exe());
? ? return Promise.all(promises);
? }
}
// 使用示例
const rec = new Reciever(); // 創(chuàng)建請(qǐng)求接收者
const rM = new RM(); // 創(chuàng)建請(qǐng)求管理者
// 添加具體請(qǐng)求命令
rM.add(new RCd(rec, 'data1'));
rM.add(new RCd(rec, 'data2'));
rM.add(new RCd(rec, 'data3'));
rM.pReq()
? .then(() => {
? ? console.log('所有請(qǐng)求已完成');
? })
? .catch((error) => {
? ? console.error('請(qǐng)求出錯(cuò):', error);
? });

代碼舉例3:

使用命令設(shè)計(jì)模式實(shí)現(xiàn)撤銷和重做,用到了棧數(shù)據(jù)結(jié)構(gòu),如下所示:

// 命令接口:想要用命令策略實(shí)現(xiàn)撤銷、重做就必須先在抽象接口中定義好撤銷的接口
abstract class Cmd {
? abstract exe(): void;
? abstract undo(): void;
}
// 具體命令類 - 加法命令
class AddCmd extends Cmd {
? constructor(public rec: Rec, public value: number) {
? ? super();
? }
? exe() {
? ? this.rec.add(this.value);
? }
? undo() {
? ? this.rec.subtract(this.value);
? }
}
// 接收者類
class Rec {
? result = 0;
? add(value: number) { this.result += value }
? subtract(value: number) { this.result -= value }
}
// 調(diào)用者/發(fā)送者
class Invoker {
? cmds: Cmd[] = [];
? xcmd: Cmd[] = [];
? exe(cmd: Cmd) {
? ? cmd.exe();
? ? this.cmds.push(cmd);
? }
? // 重點(diǎn)
? undo() {
? ? const cmd = this.cmds.pop();
? ? if (!cmd) return;
? ? cmd.undo();
? ? this.xcmd.push(cmd);
? }
? // 重點(diǎn)
? redo() {
? ? const cmd = this.xcmd.pop();
? ? if (cmd) {
? ? ? cmd.exe();
? ? ? this.cmds.push(cmd);
? ? }
? }
}
// 示例用法
const rec = new Rec(); // 創(chuàng)建接收者對(duì)象
const ivk = new Invoker(); // 創(chuàng)建調(diào)用者對(duì)象
const addCmd = new AddCmd(rec, 5); // 創(chuàng)建加法命令
ivk.exe(addCmd); // 執(zhí)行加法命令,結(jié)果為:5
ivk.undo(); // rec.result = 0
ivk.redo(); // rec.result = 5

命令設(shè)計(jì)模式和策略設(shè)計(jì)模式的不同:

  • 命令設(shè)計(jì)模式的最小操作單元是【命令對(duì)象】;而策略設(shè)計(jì)模式的最小操作單元是方法,或者算法。

  • 命令設(shè)計(jì)模式一次只操作一個(gè)命令對(duì)象;而策略設(shè)計(jì)模式為了完成任務(wù)可以組合多個(gè)策略。

  • 命令設(shè)計(jì)模式一般不會(huì)將某個(gè)命令單獨(dú)保存到內(nèi)部狀態(tài)中;而策略設(shè)計(jì)模式必須保存當(dāng)前的策略。

  • 使用命令設(shè)計(jì)模式可以實(shí)現(xiàn)撤銷、重做等功能、這反映出各個(gè)命令之間是平等關(guān)系;而策略設(shè)計(jì)模式的各個(gè)策略之間可能是先后順序關(guān)系。

原生使用

下面這些是 JavaScript 中常見的原生部分,它們?cè)谀撤N程度上使用到了命令模式的思想和機(jī)制。通過封裝行為成具體的對(duì)象并在需要時(shí)進(jìn)行調(diào)用,這些原生功能可以提供更靈活、可擴(kuò)展的方式來處理相關(guān)的請(qǐng)求或操作。

  • 事件處理:JavaScript 中的事件處理機(jī)制可以看作是一種命令模式的應(yīng)用。當(dāng)用戶與頁面進(jìn)行交互時(shí),例如點(diǎn)擊按鈕、鍵盤按鍵或鼠標(biāo)移動(dòng)等,事件被觸發(fā)并執(zhí)行相應(yīng)的處理函數(shù)。這里事件就充當(dāng)了命令對(duì)象,而事件處理函數(shù)則扮演著命令的接收者。

  • XMLHttpRequest 對(duì)象:在早期的 Ajax 開發(fā)中,我們常使用 XMLHttpRequest 對(duì)象來進(jìn)行異步請(qǐng)求。開發(fā)者可以將每個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,并通過調(diào)用 send() 方法來發(fā)送請(qǐng)求。這里的 XMLHttpRequest 對(duì)象和 send() 方法即可看作是命令模式的實(shí)現(xiàn),發(fā)送請(qǐng)求的行為被封裝成具體的命令對(duì)象。

  • History API:瀏覽器的 History API 提供了對(duì)瀏覽器歷史記錄的控制。通過調(diào)用 pushState() 或 replaceState() 方法,我們可以添加或替換瀏覽器的歷史記錄條目,并關(guān)聯(lián)相應(yīng)的狀態(tài)數(shù)據(jù)。這里的 pushState() 和 replaceState() 方法可以看作是命令對(duì)象,用于執(zhí)行添加或替換歷史記錄的操作。

  • document.execCommand():Document 對(duì)象的 execCommand() 方法允許在網(wǎng)頁中執(zhí)行命令式的編輯操作,如粘貼、剪切、加粗、斜體等。開發(fā)者可以調(diào)用 execCommand() 方法并傳遞相應(yīng)的命令參數(shù)來執(zhí)行這些操作,從而實(shí)現(xiàn)富文本編輯功能。

  • setTimeout() 和 setInterval():JavaScript 提供了 setTimeout() 和 setInterval() 函數(shù)來實(shí)現(xiàn)定時(shí)器功能。開發(fā)者可以使用這兩個(gè)函數(shù)將一段代碼封裝成一個(gè)函數(shù)對(duì)象,并在指定的時(shí)間間隔后執(zhí)行相應(yīng)的代碼,相當(dāng)于將定時(shí)器行為封裝成具體的命令對(duì)象。

業(yè)務(wù)實(shí)踐:

  • 按鈕和用戶交互:當(dāng)你需要實(shí)現(xiàn)一個(gè)具有撤銷、重做或記錄操作歷史的按鈕交互功能時(shí),可以使用命令模式。每個(gè)按鈕可以表示一個(gè)命令對(duì)象,按下按鈕時(shí)執(zhí)行相應(yīng)的命令操作。

也就是說但凡見到按鈕,都可以使用命令設(shè)計(jì)模式。

  • 異步請(qǐng)求管理:當(dāng)你需要對(duì)異步請(qǐng)求進(jìn)行批處理、隊(duì)列化或延遲執(zhí)行時(shí),命令模式可以很好地組織和管理這些請(qǐng)求。將每個(gè)請(qǐng)求封裝成一個(gè)命令對(duì)象,并使用命令隊(duì)列來依次執(zhí)行這些命令。

  • 菜單和快捷鍵:當(dāng)你需要實(shí)現(xiàn)復(fù)雜的菜單系統(tǒng)或支持快捷鍵操作時(shí),命令模式可以幫助你處理不同的菜單項(xiàng)或快捷鍵動(dòng)作。每個(gè)菜單項(xiàng)或快捷鍵可以關(guān)聯(lián)一個(gè)命令對(duì)象,觸發(fā)時(shí)執(zhí)行相應(yīng)的命令操作。

  • 動(dòng)畫控制:當(dāng)你需要控制頁面元素的復(fù)雜動(dòng)畫序列或狀態(tài)切換時(shí),命令模式可以提供一種有效的方式。每個(gè)動(dòng)畫或狀態(tài)切換可以封裝成一個(gè)命令對(duì)象,通過調(diào)用者來觸發(fā)執(zhí)行。

  • 歷史記錄與撤銷:當(dāng)你需要實(shí)現(xiàn)撤銷和重做功能或記錄用戶操作歷史時(shí),命令模式非常有用。每個(gè)用戶操作可以表示一個(gè)命令對(duì)象,并在執(zhí)行時(shí)更新狀態(tài)或記錄操作,以便支持撤銷和重做操作。

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

相關(guān)文章

最新評(píng)論