前言 博客园谈设计模式的文章很多,我也受益匪浅,包括TerryLee、吕震宇等等的.NET设计模式系列文章,强烈推荐。对于我,擅长于前台代码的开发,对于设计模式也有一定的了解,于是我想结合Javascript来设计前台方面的"设计模式",以对后台"设计模式"做个补充。开始这个系列我也诚惶诚恐,怕自己写得不好,不过我也想做个尝试,一来希望能给一些人有些帮助吧,二来从写文章中锻炼下自己,三来通过写文章对自己增加自信;如果写得不好,欢迎拍砖,我会虚心向博客园高手牛人们学习请教;如果觉得写得还可以,谢谢大家的支持了:)
今天开始介绍命令模式,并且将利用命令模式设计一个简单的在线编辑器。
概述
在各种各样的行为实现中,行为请求者与行为实现者紧密耦合,当每增加一个行为实现的时候,行为请求者必须增加一个对行为的处理,这样就需要大量改动请求者的操作,显然这样不利于维护和扩展。为了让行为请求者和行为实现者解耦,可以将行为封装为一个命令对象,但需要处理行为时,只要请求者知道命令对象,它本身不需要知道命令对象都做些什么,命令对象负责执行 接收者 的真正实现,这样就达到二者之间松耦合的目的。
定义
命令模式是将请求封装成对象,这可以让你使用不同请求、队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。
类图
实例分析
现在开始利用命令模式来应用到一个在线编辑器的场景中,并且详细分析一下:
这里先给大家看下效果图(兼容多浏览器):
这里我引用了我的第4篇-组合模式的菜单例子进行改进;将命令模式和组合模式相结合的方式来阐述例子。
其中主菜单包括: 文件(子菜单:新建、导出、退出)
编辑(子菜单:剪切、复制、粘贴、删除)
格式(子菜单:字体、字号、加粗、斜体、下划线、位置、编号、字体颜色)
插入(子菜单:插入链接、插入图片),操作(撤销、重做、切换HTML)
自定义格式(子菜单:格式1)
帮助(子菜单:关于作者)
编辑器的这些功能实际上很常用。最后点击"得到HTML值"的按钮,可以得到HTML的内容,这里就可以按照您的需要来存储编辑器内容;文章的最后我将附上源代码。
1. 首先添加一个ICommand.js文件,其中定义一个Command接口: 其中execute作为Command执行的接口方法;
关于接口的定义,可以参考我的第0篇-面向对象基础以及接口和继承类的实现的实现。
2. 添加一个ConcreteCommand.js文件,作为继承ICommand接口的所有具体实现类:
因为子菜单中的每个按钮都可作为一个具体实现类,那么我以"加粗"按钮为例,就可以得到: //加粗
function onBoldCommand() {
Interface.registerImplements(this, ICommand);
}
onBoldCommand.prototype.execute = function() {
var editor = window.frames["HtmlEditor"];
editor.document.execCommand("Bold", false, false);
editor.focus();
};
其中Interface.registerImplements(this, ICommand);说明它继承于ICommand接口,而execute方法作为基于接口方法的具体实现,这里实现了文档加粗功能;
3. 现在要创建"主菜单"和"子菜单",Menu类和MenuItem类,注意这里"子菜单"也可能是Menu类,比如"格式"主菜单下的"位置"下面还包括下级菜单"居左对齐","居中对齐","居右对齐"等等,所以作为"叶子"结点的菜单就以MenuItem类来实现:
Menu类的实现如下: function Menu(text, title, href) {
this.menuComponents = new Array();
this.text = text;
this.title = title;
this.href = href;
Interface.registerImplements(this, MenuComponent);
}
Menu.prototype = {
getElement : function() {
if(this.menuComponents.length == 0)
{
throw new Error(this.text + "菜单下没有子菜单");
}
var liElement = document.createElement("li");
liElement.className = "Menu-WithChildren";
liElement.title = this.title;
var anchor = document.createElement("a");
anchor.className = "Menu-Link";
anchor.href = this.href;
liElement.appendChild(anchor);
anchor.innerHTML = this.text;
var ulElement = document.createElement("ul");
liElement.appendChild(ulElement);
for(var i = 0, len = this.menuComponents.length; i
!
最后祝:大家在新的一年里,工作顺利,事业进步,牛年牛运!Fighting!!!
参考文献:《Head First Design Pattern》
《Professional Javascript Design Patterns》
本系列文章转载时请注明出处,谢谢合作!
今天开始介绍命令模式,并且将利用命令模式设计一个简单的在线编辑器。
概述
在各种各样的行为实现中,行为请求者与行为实现者紧密耦合,当每增加一个行为实现的时候,行为请求者必须增加一个对行为的处理,这样就需要大量改动请求者的操作,显然这样不利于维护和扩展。为了让行为请求者和行为实现者解耦,可以将行为封装为一个命令对象,但需要处理行为时,只要请求者知道命令对象,它本身不需要知道命令对象都做些什么,命令对象负责执行 接收者 的真正实现,这样就达到二者之间松耦合的目的。
定义
命令模式是将请求封装成对象,这可以让你使用不同请求、队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。
类图
实例分析
现在开始利用命令模式来应用到一个在线编辑器的场景中,并且详细分析一下:
这里先给大家看下效果图(兼容多浏览器):
这里我引用了我的第4篇-组合模式的菜单例子进行改进;将命令模式和组合模式相结合的方式来阐述例子。
其中主菜单包括: 文件(子菜单:新建、导出、退出)
编辑(子菜单:剪切、复制、粘贴、删除)
格式(子菜单:字体、字号、加粗、斜体、下划线、位置、编号、字体颜色)
插入(子菜单:插入链接、插入图片),操作(撤销、重做、切换HTML)
自定义格式(子菜单:格式1)
帮助(子菜单:关于作者)
编辑器的这些功能实际上很常用。最后点击"得到HTML值"的按钮,可以得到HTML的内容,这里就可以按照您的需要来存储编辑器内容;文章的最后我将附上源代码。
1. 首先添加一个ICommand.js文件,其中定义一个Command接口: 其中execute作为Command执行的接口方法;
关于接口的定义,可以参考我的第0篇-面向对象基础以及接口和继承类的实现的实现。
2. 添加一个ConcreteCommand.js文件,作为继承ICommand接口的所有具体实现类:
因为子菜单中的每个按钮都可作为一个具体实现类,那么我以"加粗"按钮为例,就可以得到: //加粗
function onBoldCommand() {
Interface.registerImplements(this, ICommand);
}
onBoldCommand.prototype.execute = function() {
var editor = window.frames["HtmlEditor"];
editor.document.execCommand("Bold", false, false);
editor.focus();
};
其中Interface.registerImplements(this, ICommand);说明它继承于ICommand接口,而execute方法作为基于接口方法的具体实现,这里实现了文档加粗功能;
3. 现在要创建"主菜单"和"子菜单",Menu类和MenuItem类,注意这里"子菜单"也可能是Menu类,比如"格式"主菜单下的"位置"下面还包括下级菜单"居左对齐","居中对齐","居右对齐"等等,所以作为"叶子"结点的菜单就以MenuItem类来实现:
Menu类的实现如下: function Menu(text, title, href) {
this.menuComponents = new Array();
this.text = text;
this.title = title;
this.href = href;
Interface.registerImplements(this, MenuComponent);
}
Menu.prototype = {
getElement : function() {
if(this.menuComponents.length == 0)
{
throw new Error(this.text + "菜单下没有子菜单");
}
var liElement = document.createElement("li");
liElement.className = "Menu-WithChildren";
liElement.title = this.title;
var anchor = document.createElement("a");
anchor.className = "Menu-Link";
anchor.href = this.href;
liElement.appendChild(anchor);
anchor.innerHTML = this.text;
var ulElement = document.createElement("ul");
liElement.appendChild(ulElement);
for(var i = 0, len = this.menuComponents.length; i
!
最后祝:大家在新的一年里,工作顺利,事业进步,牛年牛运!Fighting!!!
参考文献:《Head First Design Pattern》
《Professional Javascript Design Patterns》
本系列文章转载时请注明出处,谢谢合作!