js命令模式
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
从命令模式的结构图可以看出,它涉及到五个角色,它们分别是:
- 客户角色:发出一个具体的命令并确定其接受者。
- 命令角色:声明了一个给所有具体命令类实现的抽象接口
- 具体命令角色:定义了一个接受者和行为的弱耦合,负责调用接受者的相应方法。
- 请求者角色:负责调用命令对象执行命令。
- 接受者角色:负责具体行为的执行。
在下面的情况下可以考虑使用命令模式:
- 系统需要支持命令的撤销(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo方法吧命令所产生的效果撤销掉。命令对象还可以提供redo方法,以供客户端在需要时,再重新实现命令效果。
- 系统需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命周期。意思为:原来请求的发出者可能已经不存在了,而命令对象本身可能仍是活动的。这时命令的接受者可以在本地,也可以在网络的另一个地址。命令对象可以串行地传送到接受者上去。
- 如果一个系统要将系统中所有的数据消息更新到日志里,以便在系统崩溃时,可以根据日志里读回所有数据的更新命令,重新调用方法来一条一条地执行这些命令,从而恢复系统在崩溃前所做的数据更新。
- 系统需要使用命令模式作为“CallBack(回调)”在面向对象系统中的替代。Callback即是先将一个方法注册上,然后再以后调用该方法。
C#命令模式:
namespace 命令模式
{
class Program
{
static void Main(string[] args)
{
//开店前的准备
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter(); //开门营业 顾客点菜
girl.SetOrder(bakeMuttonCommand1);
girl.SetOrder(bakeMuttonCommand2);
girl.SetOrder(bakeChickenWingCommand1); //点菜完闭,通知厨房
girl.Notify(); Console.Read(); }
} //服务员
public class Waiter
{
private IList<Command> orders = new List<Command>(); //设置订单
public void SetOrder(Command command)
{
if (command.ToString() == "命令模式.BakeChickenWingCommand")
{
Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤。");
}
else
{
orders.Add(command);
Console.WriteLine("增加订单:" + command.ToString() + " 时间:" + DateTime.Now.ToString());
}
} //取消订单
public void CancelOrder(Command command)
{
orders.Remove(command);
Console.WriteLine("取消订单:" + command.ToString() + " 时间:" + DateTime.Now.ToString());
} //通知全部执行
public void Notify()
{
foreach (Command cmd in orders)
{
cmd.ExcuteCommand();
}
}
} //抽象命令
public abstract class Command
{
protected Barbecuer receiver; public Command(Barbecuer receiver)
{
this.receiver = receiver;
} //执行命令
abstract public void ExcuteCommand();
} //烤羊肉串命令
class BakeMuttonCommand : Command
{
public BakeMuttonCommand(Barbecuer receiver)
: base(receiver)
{ } public override void ExcuteCommand()
{
receiver.BakeMutton();
}
} //烤鸡翅命令
class BakeChickenWingCommand : Command
{
public BakeChickenWingCommand(Barbecuer receiver)
: base(receiver)
{ } public override void ExcuteCommand()
{
receiver.BakeChickenWing();
}
} //烤肉串者
public class Barbecuer
{
public void BakeMutton()
{
Console.WriteLine("烤羊肉串!");
} public void BakeChickenWing()
{
Console.WriteLine("烤鸡翅!");
}
}
}
Javascript中的命令模式
var bindClick = function(button,func){
button.onclick = func;
}; var MenuBar = {
refresh:function(){
console.log('刷新菜单界面');
}
}; var SubMenu = {
add:function(){
console.log('增加子菜单');
},
del:function(){
console.log('删除子菜单');
}
}; bindClick(button1,MenuBar.refresh);
bindClick(button2,SubMenu.add);
bindClick(button3,SubMenu.del);
命令模式的由来,其实是回调(callback)函数的一个面向对象的替代品。
用闭包实现的命令模式如下代码所示:
var setCommand = function(button,func){
button.onclick = function(){
func();
}
}; var MenuBar = {
refresh:function(){
console.log('刷新菜单界面');
}
}; var RefreshMenuBarCommand = function(receiver){
return function(){
receiver.refresh();
}
}; var refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar); setCommand(button1,refreshMenuBarCommand);
将来有可能还要提供撤销的命令等操作。那我们最好还是把执行函数改为调用execute方法:
var RefreshMenuBarCommand = function(receiver){
return{
execute:function(){
receiver.refresh();
}
}
}; var setCommand = function(button,command){
button.onclick = function(){
command.execute();
}
}; var refreshMenuCommand = RefreshMenuBarCommand(MenuBar);
setCommand(button1,refreshMenuCommand);
撤销命令
var ball = document.getElementById('ball');
var pos = document.getElementById('pos');
var moveBtn = document.getElementById('moveBtn'); var moveCommand = function(receiver,pos){
this.receiver = receiver;
this.pos = pos;
}; moveCommand.prototype.execute = function(){
this.receiver.start('left',this.pos,1000,'strongEaseOut');
}; var moveCommand; moveBtn.onclick = function(){
var animate = new Animate(ball);
moveCommand = new MoveCommand(animate,pos.value);
moveCommand.execute();
};
撤销操作的实现一般是给命令对象增加一个名为unexcude或者undo的方法,在该方法里执行execute的反向操作。
<script>
var ball = doucment.getElementById('ball');
var pos = doucment.getElementById('pos');
var moveBtn = doucment.getElementById('moveBtn');
var cancelBtn = doucment.getElementById('cancelBtn'); var MoveCommand = function(receiver,pos){
this.receicer = receiver;
this.pos = pos;
this.oldPos = null;
}; MoveCommand.prototype.execute = function(){
this.receiver.start('left',this.pos,1000,'strongEaseOut');
this.oldPos = this.receiver.dom.getBoundingClientRect()[this.receiver.propertyName];
//记录小球开始移动前的位置
}; MoveCommand.prototype.undo = function(){
this.receiver.start('left',this.oldPos.1000,'strongEaseOut');
//回到小球移动前记录位置
}; var moveCommand; moveBtn.onclick = function(){
var animate = new Animate(ball);
moveCommand = new MoveCommand(animate,pos.value);
moveCommand.execute();
}; cancelBtn.onclick = function(){
moveCommand.undo(); //撤销命令
};
</script>
撤销和重做
比如在一个围棋程序中,现在已经下了10步棋,我们需要一次性悔棋到第5步。在这之前,我们可以把所有执行过的下棋命令都存储在一个历史列表 中,Cnavas画图的程序中,我们却很难为这里的命令对象定义一个擦除某条曲线的undo操作,这时候最好的办法是先清除画布,然后把刚才执行过的命令 全部重新执行一遍,这一点同样可以利用一个历史列表堆栈办到。这是逆转不可逆命令的一个好办法。
<html>
<body>
<button id="replay">播放录像</button>
</body>
<script>
var Ryu = {
attack:function(){
console.log('攻击');
},
defense:function(){
console.log('防御');
},
jump:function(){
console.log('跳跃');
},
crouch:function(){
console.log('蹲下');
}
}; var makeCommand = function(receiver,state){ //创建命令
return function(){
receiver[state]();
}
}; var commands = {
"119":"jump", //W
"115":"crouch", //S
"97":"defense", //A
"100":"attack" //D
}; var commandStack = []; //保存命令的堆栈 document.onkeypress = function(ev){
var keyCode = ev.keyCode,
command = makeCommand(Ryu,commands[keyCode]); if(command){
command(); //执行命令
commandStack.push(command); //将刚刚执行过的命令保存进堆栈
}
}; document.getElementById('replay').onclick = function(){ //点击播放录像
var command;
while(command = commandStack.shift()){ //从堆栈里依次取出命令并执行
command();
}
};
</script>
</html>
命令队列
一个动画结束后该如何通知队列。通常可以使用回调函数来通知队列,除了回调函数之外,还可以选择发布-订阅模式。即在一个动画结束后发布一个消息,订阅者接收到这个消息之后,便开始执行队列里的下一个动画。
宏命令
宏命令是一组命令的集合,通过执行宏命令的方式,可以一次执行一批命令。
var closeDoorCommand = {
execute:function(){
console.log('关门');
}
}; var openPcCommand = {
execute:function(){
console.log('开电脑');
}
}; var openQQCommand = {
execute:function(){
console.log('登录QQ');
}
}; var MacroCmmand = function(){
return{
commandsList:[],
add:function(command){
this.commandsList.push(command);
},
execute:function(){
for(var i=0,command;command = this.commandsList[i++];){
command.execute();
}
}
}
}; var macroCommand = MacroCommand();
macroCommand.add(closeDoorCommand);
macroCommand.add(openPcCommand);
macroCommand.add(openQQCommand); macroCommand.execute();
宏命令是命令模式与组合模式的联用产物。
智能命令与傻瓜命令
一般来说,命令模式都会在command对象中保存一个接收者来负责真正执行客户的请求,这种情况下命令对象是“傻瓜式”的,它只负责把客
户的请求转交给接收者来执行,这种模式的好处是请求发起者和请求接收者之间尽可能地得到了解耦。
但是我们也可以定义一些更“聪明”的命令对象,“聪明”的命令对象可以直接实现请求,这样一来就不再需要接收者的存在,这种“聪明
”的命令对象也叫作智能命令。
js命令模式的更多相关文章
- JS命令模式个人理解
JS命令模式个人理解 //BODY部分<body> <button id="execute">打开电视</button> <button ...
- js 命令模式 组合模式
* 基本宏命令 var closeDoorCommand = { execute: function() { console.log("Closing the door..."); ...
- js设计模式-命令模式
命令模式是一种组织型模式,主要用在把调用对象(用户界面.API和代理等)与实现操作的对象隔离开.也就是说 ,凡是两个对象间的互动方式需要更高的模块化程度时都可以用到这种模式. 命令模式的好处:1.提高 ...
- 大熊君说说JS与设计模式之------命令模式Command
一,总体概要 1,笔者浅谈 日常生活中,我们在看电视的时候,通过遥控器选择我们喜欢的频道时,此时我们就是客户端的角色,遥控器的按钮相当于客户请求,而具体执行的对象就是命令对象, 命令模式把一个请求或者 ...
- js设计模式(11)---命令模式
0.前言 早上好,早晨的时光总是美好的,坐在空调屋里,看着外边的蓝天白云,不停地敲击着键盘,多么美好地享受,也许屌丝就是如此容易满足. 1.什么是命令模式? 用于将一个请求封装为一个对象,从而可用不同 ...
- JS 设计模式五 -- 命令模式
概念 命令模式中的命令(command) 指的是 一个执行某些待定事情的指令. 用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系. 例子 假设html结构如下: &l ...
- js设计模式(六)---命令模式
命令模式算是最简单.优雅的模式之一了,命令模式中的命令指的是一个执行某些特定事情的指令.目的是吧请求发送者和请求接受者解耦, 就像点餐,顾客只需要发送菜单,谁去接收,不用考虑.厨师接收到命令开始做菜, ...
- JS设计模式(6)命令模式
什么是命令模式? 定义:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化. 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录. ...
- 浅谈js设计模式 — 命令模式
命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么.此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦 ...
随机推荐
- view {display:block}
view {display:block}
- SSL逐渐演变到TLS
w https://zh.wikipedia.org/wiki/超文本传输安全协议
- sqlbulk的问题
今天在bulk的时候遇到一个很“奇怪”的问题 无论怎样修改传入的值,也会报类型转换的错误.后来 在此文中找到了正解 bbs.csdn.net/topics/390430064 SqlBulkCopy不 ...
- <2013 07 22> 游历西欧
从本月11号开始到昨天,10天时间,和其他六位同学畅游了西欧,路经慕尼黑-巴塞罗马-尼斯-马赛-巴黎-阿姆斯特丹,最后回到慕尼黑,每个地方都待了两天,参观了主要的景点和建筑,见识了本地文化与饮食. 令 ...
- BigDecimal使用整理
BigDecimal使用整理 一. BigDecimal简介 计算机计算中无论是float还是double都是浮点数,由于计算机是二进制的,导致在在浮点数计算时会出现精度丢失,因此引入BigD ...
- PS导出@3x、@2x、@1x格式的iOS切图神器-Retinize
Retinize动作下载地址:http://retinize.it/ 使用:ps-载入动作-选中图片-执行动作
- 关于:before :after
首先要明白一种思想:结构和样式分离. 结构和样式分离,就意味着:没有样式表,HTML文档也是一个完整的文档:没有样式表,也能正常阅读用HTML表达的所有内容.明白这种思想就能很好理解样式表中使用--- ...
- 深入理解MVC架构
MVC MVC是一种设计模式(Design pattern),也就是一种解决问题的方法和思路, 是上世纪80年代提出的,到现在已经颇有历史了. MVC的意义在于指导开发者将数据与表现解耦,提高代码,特 ...
- phoneGap实现离线缓存
引自:http://www.iteye.com/topic/1128173 正在做一个跨平台的应用,需要使用phonegap进行文件的一些基本操作. 需求如下:可以选择本地图片,或者从相机选择图片,并 ...
- bacula 备份恢复
一.数据恢复: 在bacula服务器执行: /opt/bacula/etc/ bconsole #进入交互窗口 *restore #输入restore恢复命令 Automatically select ...