命令模式
提出问题
在编写程序的过程中,我们经常会让某个对象去调用其他对象的方法。有时候,我们可能会调用不同对象的方法,需要随时进行替换。比如说,我单击了界面上的一个按钮,按钮作为一个界面控件,可以具有不同的功能。有时候它被用作是提交按钮,有时候也可以是关闭按钮。如果我直接写死,这个按钮被点击之后是提交。那如果我需要一个关闭按钮,就需要全部重写(直接复制之前的代码加以改动也算全部重写,因为代码还是冗余的)。
怎么解决代码冗余的问题呢?
解决问题
想一想,我们需要改变的只是按钮被点击后的行为。那么,我们是不是可以把这一块封装起来,作为一个单独的对象?我们不妨叫他命令对象。
每次按钮被点击后,就去调用这个命令对象中预先设置好的方法。如果要更换按钮点击后的行为,只需要更换命令对象即可。
下面是代码示例:
class Window { closeWindow() { } } class Command { constructor() { this.window = new Winodw; } exec() { window.closeWindow(); } } class Button { constructor(command) { this.command = command; } click() { this.command.exec(); } }
let closeWindowCommand = new Command(); let button = new Button(closeWindowCommand); button.click();
|
命令队列
除了实现让一个对象发起不同的请求以外,有时候我们可能希望一个对象能发起一系列请求。并且在程序运行中,我们能动态的增加与删除这些请求。
这时候,我们可以把原来的命令改成一个命令队列(数组),每次请求时,逐个执行队列中的命令。
下面是个例子:
class Submit { submit() { } } class Window { closeWindow() { } } class Command { constructor() { this.window = new Winodw; } exec() { window.closeWindow(); } } class Button { constructor(command) { this.commands = [command]; } addCommand(command) { this.commands.push(command); } click() { this.commands.forEach(command=>command.exec()); } }
let closeWindowCommand = new Command(); let button = new Button(closeWindowCommand); button.click();
|
实现Undo
只需要在Command上增加Undo方法即可。直接上例子:
class Calculator { constructor() { this.result = 0; } add(val) { this.result += val; } sub(val) { this.result -= val; } } class AddCommand { constructor(calculator) { this.val = 0; this.calculator = calculator; } exec(val) { this.val = val; this.calculator.add(val) } undo() { this.calculator.sub(this.val); } }
class Button { constructor(command) { this.command = command; } click() { this.command.exec(); } }
let cal = new Calculator(); let command = new AddCommand(cal); let button = new Button(command); button.click();
|