一、命令模式使用场景及定义

  命令模式常见的使用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接受者是谁,也不知道请求的具体操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求的发送者和请求接受者可以解除彼此之间的耦合关系。

  命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分隔开。请求的一方不必知道接收请求一方的接口,更不必知道请求是怎么被接收的,以及操作是否被执行,何时被执行,以及是如何执行的。

  命令模式使得请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。由于对象的生命周期在程序运行期间是一直存在的,因此可以在需要的任何时间执行。

  适用场景:

  1.系统需要将请求调用者和请求接收者解耦,使得二者不直接交互。

  2.系统需要在不同的时刻指定请求,将请求排队和执行请求。

  3.系统需要支持命令的撤销(undo)和恢复(redo)操作。

  4.系统需要将一组操作组合在一起,即支持宏命令。

这些优点归根结底在于我们将命令封装成了对象,

命令模式中,命令的请求发出者不直接与命令的接收者交互,而是与命令对象交互。

命令对象一般持有接收者(java中,接收者一般作为命令对象的一个属性);javascript中接收者可以作为函数的参数传递。

通过命令对象将命令请求发出者与命令接收者以松耦合的方式联系起来,因为命令对象的生命周期几乎是永久的,除非我们主动去回收它,因此命令对象的生命周期跟请求初始发生的时间无关。可以进行命令的排队、重做、取消等操作。

二、java中的命令模式

  参见博客:http://blog.csdn.net/jason0539/article/details/45110355

  角色:

  Command 定义命令的接口,声明execute等方法;

  ConcreteConmand 实现命令接口,通常会持有接收者,并调用接收者的功能来实现相应的功能。

  Receiber 接口者,命令真正的执行对象。

  Invoker 通常会持有命令对象,可以持有很多得命令对象,相当于使用命令对象的入口;可以对命令对象进行排队等操作。

  Clinet 创建具体的命令对象,并为其设置接收者。从这个角度上来说,称之为“装配者”更为贴切。

  java命令模式的使用案例(模拟对计算机的操作有开机,关机,换台等命令)

package com.bobo.shejimoshi;
//命令接收者Receiver,要是真正执行命令的对象
public class Tv {
public int currentChannel=;
public void turnOn(){
System.out.println("the tv is on");
}
public void turnOff(){
System.out.println("the tv is off");
}
public void changeChannel(int channel){
this.currentChannel=channel;
System.out.println("Now tv channel is "+channel);
}
}
package com.bobo.shejimoshi;
//执行命令的抽象接口
public interface Command {
void execute();
}
package com.bobo.shejimoshi;
//命令接口的实现对象
public class CommandOn implements Command{
private Tv myTv;
public CommandOn(Tv tv){
myTv=tv;
}
@Override
public void execute() {
// TODO Auto-generated method stub
myTv.turnOn();
} }
package com.bobo.shejimoshi;
//命令接口的实现对象
public class CommandOff implements Command{
private Tv myTv;
public CommandOff(Tv tv){
myTv=tv;
}
@Override
public void execute() {
myTv.turnOff();
} }
package com.bobo.shejimoshi;
//命令接口的实现对象
public class CommandChange implements Command{
private Tv myTv;
private int channel;
public CommandChange(Tv tv,int channel){
myTv=tv;
this.channel=channel;
}
public void execute(){
myTv.changeChannel(channel);
} }
package com.bobo.shejimoshi;
//可以看做是遥控器Invoker,作为使用命令对象的入口,可以持有很多的命令对象
//根据应用场景,invoker可以进行命令的排队等
public class Control {
private Command onCommand,offCommand,changeChanelCommand;
public Control(Command on, Command off,Command channel){
onCommand=on;
offCommand=off;
changeChanelCommand=channel;
} public void turnOn(){
onCommand.execute();
} public void turnOff(){
offCommand.execute();
} public void changeChannel(){
changeChanelCommand.execute();
} }
package com.bobo.shejimoshi;
//测试类client,
public class Client { public static void main(String[] args) {
//命令接收者receiver
Tv myTv=new Tv();
CommandOn on=new CommandOn(myTv);
CommandOff off=new CommandOff(myTv);
CommandChange chanel=new CommandChange(myTv,);
Control control=new Control(on,off,chanel);
//开机
control.turnOn();
//关机
control.turnOff();
//调台
control.changeChannel(); } }

三、javascript中的命令模式

javascript作为函数作为一等公民的语言,命令模式已经融入到语言的设计中。在面向对象的语言如java中,命令模式的接收者被当做command对象的属性保存起来,同时约定执行命令的操作调用command.execute方法,在javascript中,接收者可以封闭在闭包产生的环境中,执行命令的操作可以更加简便,仅仅执行回调函数即可。并且运算块可以封装在command.execute方法中,也可以封装在普通函数中。

//命令模式的学习
var tv = (function() {
var turnOn = function() {
console.log('打开电视机');
};
var turnOff = function() {
console.log('关闭电视机');
};
var changeChannel = function(channel) {
console.log('当前电视频道为' + channel);
};
return {
'turnOn': turnOn,
'turnOff': turnOff,
'changeChannel': changeChannel
}
})();
var TurnOnCommand = function(receiver) {
return function() {
receiver.turnOn();
}; };
var TurnOffCommand = function(receiver) {
return function() {
receiver.turnOff();
}; };
var changeChannelCommand = function(receiver, channel) {
return function() {
receiver.changeChannel(channel);
}; }; //测试
var setCommand = function(button, func) {
button.onclick = function() {
func();
};
}; var button = document.getElementById('btn');
var turnOnCmd = TurnOnCommand(tv);
var turnOffCmd = TurnOffCommand(tv);
var changeChannelCmd = changeChannelCommand(tv, );
setCommand(button, changeChannelCommand); //可以将命令加入队列,依次执行
var commandsQueue=[];
commandsQueue.push(changeChannelCmd);
commandsQueue.push(turnOnCmd);
commandsQueue.push(turnOffCmd); while(command=commandsQueue.shift()){
command();
}

当然,考虑到除了执行命令之外,将来还可能提供撤销等操作,因此最好还是把执行函数改为调用execute方法,代码如下:

//实现单例模式
var tv=(function(){
var turnOn=function(){
console.log('打开电视机');
};
var turnOff=function(){
console.log('关闭电视机');
};
var changeChanel=function(channel){
console.log('当前电视频道为:'+channel);
};
return{
turnOn:turnOn,
turnOff:turnOff,
changeChanel:changeChanel
};
})(); var TurnOnCommand=function(receiver){
return {
execute:function(){
receiver.turnOn();
}
};
};
var TurnOffCommand=function(receiver){
return {
execute:function(){
receiver.turnOff();
}
};
};
var ChangeChanelCommand=function(receiver,channel){
return {
execute:function(){
receiver.changeChanel(channel);
}
};
}; function setCommand(btn,command){
btn.addEventListener('click',function(){
command.execute();
});
}
var turnOnCmd=new TurnOnCommand(tv);
var turnOffCmd=new TurnOffCommand(tv);
var changeChanelCmd=new ChangeChanelCommand(tv,);
var btn=document.getElementById('btn');
setCommand(btn,changeChanelCmd);

通过实践,发现javascript中的命令模式:

执行命令的操作大多数时候不是以命令对象的方式存在,很可能就是一个回调函数,从表面看起来甚至不太注意到这是命令模式。

在自己封装的动画类中,每一次执行动画的命令操作就是一个回调函数(函数保存有命令执行者的引用,不论是通过函数参数访问到命令执行者,或者是像动画类中可通过this访问到命令执行者),通过数组将动画执行操作进行排队;

在自己封装的表单验证插件中,每一次执行验证的操作实际上就是formField对象的一个方法,在合适的时机(如表单提交时)调用该方法。

javascript设计模式学习之九——命令模式的更多相关文章

  1. javascript设计模式详解之命令模式

    每种设计模式的出现都是为了弥补语言在某方面的不足,解决特定环境下的问题.思想是相通的.只不过不同的设计语言有其特定的实现.对javascript这种动态语言来说,弱类型的特性,与生俱来的多态性,导致某 ...

  2. javascript设计模式学习之十——组合模式

    一.组合模式定义及使用场景 组合模式将对象组合成树形结构,用以表示“部分—整体”的层次结构,除了用来表示树形结构之外,组合模式还可以利用对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性. ...

  3. Javascript设计模式学习三(策略模式)

    定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换.目的:将算法的使用和算法的实现分离开来.比如: if(input == 'A'){ return 1; } if(input == ...

  4. javascript设计模式详解之策略模式

    接上篇命令模式来继续看下js设计模式中另一种常用的模式,策略模式.策略模式也是js开发中常用的一种实例,不要被这么略显深邃的名字给迷惑了.接下来我们慢慢看一下. 一.基本概念与使用场景: 基本概念:定 ...

  5. 设计模式学习系列6 原型模式(prototype)

    原型模式(prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.允许一个对象再创建另外一个新对象的时候根本无需知道任何创建细节,只需要请求圆形对象的copy函数皆可. 1 ...

  6. Java设计模式(22)命令模式(Command模式)

    Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体 ...

  7. C#设计模式之11:命令模式

    C#设计模式之11:命令模式 命令模式 命令模式用来解决一些复杂业务逻辑的时候会很有用,比如,你的一个方法中到处充斥着if else 这种结构的时候,用命令模式来解决这种问题就会让事情变得简单很多. ...

  8. JavaScript设计模式学习笔记

    1 JavaScript设计模式深入分析 私有属性和方法:函数有作用域,在函数内用var 关键字声明的变量在外部无法访问,私有属性和方法本质就是你希望在对象外部无法访问的变量. 特权属性和方法:创建属 ...

  9. Javascript设计模式学习一

    学习Javascript设计模式之前,需要先了解一些相关知识,面向对象的基础知识.this等重要概念,以及掌握一些函数式编程的技巧. Js多态 多态的思想:实际上是把“做什么”和“谁去做”分离开来.例 ...

随机推荐

  1. Web 在线文件管理器学习笔记与总结(11)获取文件夹信息 (12)返回上一级操作

    (11)获取文件夹信息 文件夹没有修改操作. index.php: <?php require 'dir.func.php'; require 'file.func.php'; require ...

  2. centos时间同步方法

    centos时间同步方法 电脑软硬件应用网 45IT.COM 时间:2012-12-08 18:09 作者:李本清 新装的服务器可能设置了错误的,需要调整时区并调整时间.如下是使用NTP来从一个时间服 ...

  3. BOM表生成

  4. wordpress页面前端添加编辑按钮

    <?php edit_post_link(__('Edit This')); ?> 在single.php或者page.php模板页面加入以上代码片段.当管理员登录后,可以直接点击编辑文章 ...

  5. IMP-00009: 导出文件异常结束

    今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到" IMP-00009: 导出文件异常结束" 错误,google一下,发现可能有如下原因导致 imp的数据太大,没有 ...

  6. Scrapy安装介绍

    一. Scrapy简介 Scrapy is a fast high-level screen scraping and web crawling framework, used to crawl we ...

  7. linux下线程调用sleep,进程挂起

    http://blog.csdn.net/horstlinux/article/details/7911457 http://blog.csdn.net/eroswang/article/detail ...

  8. Reactor 与 Proactor

    一.五种IO Model blocking IO nonblocking IO IO multiplexing signal driven IO(不常用) asynchronous IO 对于一个ne ...

  9. ADB not responding. If you'd like to retry, then please manually kill "adb.exe" and click 'Restart'

    ADB not responding. If you'd like to retry, then please manually kill "adb.exe" and click ...

  10. 变态的HelloWorld

    public static void main(String[] args) { int i, n[] = { (((1 << 1) << (1 << 1) < ...