读书笔记之 - javascript 设计模式 - 门面模式
门面模式有俩个作用:
- 简化类的接口
- 消除类与使用它的客户代码之间的耦合
在javascript中,门面模式常常是开发人员最亲密的朋友。它是几乎所有javascript库的核心原则,门面模式可以使库提供的工具更容易理解。使用这种模式,程序员可以间接地与一个子系统打交道,与直接访问子系统相比,这样做更不容易出错。
addEvent函数是一个基本的门面,你不用在每次为一个元素添加事件监听器的时候都得针对浏览器间的差异进行检查,有了这个便利,你可以把这个添加事件的底层细节抛在脑后,而把心思集中在如何构建自己的应用系统上。
用作便利方法的门面元素
门面模式给与开发人员的另一个好处表现在对函数的组合上。这些组合而得到的函数又叫便利函数。如下例子:
function a(){}
function b(){}
function e(){
a();
b();
}
你可能在想为什么一开始不把所有功能放到函数e中,答案是分离可以获得更多粒度控制和灵活性。组合a和b可能会对应用程序造成破坏或者产生意想不到的结果,如以DOM脚本编程中经常遇到的俩个普通事件方法为例:
- event.stopPropagation()
- event.preventDefault()
第一个stopPropagation功能是中止事件沿DOM树向上冒泡的传播过程
第二个方法preventDefault是阻止浏览器针对一个事件的默认行为。因为不同浏览器厂商为这俩个功能提供的接口略有差异,所以现在摆在我们面的就是一个门面模式实现便利方法的理想案例。
var DED = window.DED || {};
DED.util = {
stopPropagation:function(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
},
preventDefault:function(e){
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
},
stopEvent:function(e){
DED.util.stopPropagation(e);
DED.util.preventDefault(e);
}
}
尽管看起来很像,但是门面模式并不是适配器模式。适配器模式是一种包装器,用来对接口进行适配以便在不兼容的系统中使用它。而创建门面模式则是图个方便,它并不用于达到与需要特定接口的客户端系统打交道这个目的,而是用于提供一个简化的接口。
示例:设置HTML元素的样式:
不停的写getElementById并且为每一个元素设置同样的属性,看起来相当的无聊,门面模式就可以派上用场,我们采用一种逆向的工作方式,先写出使用方法,然后设计代码。
setStyle(['foo','bar','baz'],'color','red');
可以看出,要创建setStyle函数,这里传递给它的第一个参数是一个包含着三个ID值得数组。第二个参数是要设置的样式属性,而第三个参数则是该属性的值。下面这个函数就是一个门面元素,它可以满足我们的需要:
function setStyle(elements,prop,val){
for(var i=0,len=elements.length-1;i<len;++i){
document.getElementById(elements[i]).style[prop] = val;
}
}
我们可以设计一个更复杂的接口,把所有逻辑都组合在另一个门面元素中,以便一次函数调用就能处理所有这些问题。这个门面元素内部也要使用setStyle,但是客户代码对此一无所知。我们把它命名为setCSS:
setCSS(['foo'],{
position:'absolute',
top:'50px',
left:'20px'
});
setCSS的实现方式如下:
function setCSS(el,styles){
for (var prop in styles) {
if(!styles.hasOwnProperty(prop)){
continue;
}else{
setStyle(el,prop,styles[prop]);
}
}
}
设计一个事件工具:
前面曾经说过,在处理跨浏览器开发的问题时,最好创建一个门面模式,如果要设计一个大型库,那么最好把其中所有的工具元素聚拢在一起,这样更好用,访问起来也更简单。鉴于各种浏览器在事件处理方面表现出来的差异,开发一个事件工具很有必要。
我们先从一个基本的框架开始,这里要用到单体模式,它位于DED.util命名空间中,包含着我们要设计的各个静态方法:
DED.util.Event = {
// bulk goes here ...
}
接下来我们将着手解决开发人员在与事件打交道的时候都会遇到的一些常见的问题,比如怎么获得事件目标元素和事件对象。当然,我们也会利用前面用来处理事件传播和事件默认行为的代码。下面是粗略的框架结构:
DED.util.Event = {
getEvent:function(){},
getTarget:function(){},
stopPropagation:function(e){},
preventDefault:function(e){},
stopEvent:function(e){}
}
下面的代码对相关对象的能力和特性进行检查并加入一些代码分支,以图弥合浏览器之间的差异,其结果是创建了5个门面方法,这是一个更为一致的接口,有了它我们的工作就会变得更轻松。
DED.util.Event = {
getEvent:function(e){
return e||window.event;
},
getTarget:function(e){
return e.target || e.srcElement;
},
stopPropagation:function(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
},
preventDefault:function(e){
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
},
stopEvent:function(e){
this.stopPropagation(e);
this.util.preventDefault(e);
}
}
现在这个事件工具设计好了,可以和前面的addEvent函数结合使用
addEvent('example','click',function(e){
console.log(DED.util.Event.getTarget(e));
DED.util.Event.stopEvent(e);
})
实现门面模式的一般步骤:
函数名字应该仔细考虑,与他们用途要相称,对那些有几个函数组合而成的函数,一个简单的方法就是把相关函数的名称串成一个函数名,并采用camel大写规范。或者也可以使用thisFunctionAndThatFunction这种形式。
处理浏览器的API的不一致性属于另一种情况,此时要做的就是把分支代码放在新创建的门面函数中,辅以对象检查或者浏览器嗅探技术。
门面模式的适用场合:
判断是否应该使用门面模式的关键在于辨认那些反复成组出现的代码,如果函数b出现在函数a之后这种情况经常出现,那么你也许应该考虑用一个门面函数把这俩个函数组合起来。
使用门面模式的好处就是,编写一次组合代码,可以反复使用。避免与下层子系统的紧密耦合。
读书笔记之 - javascript 设计模式 - 门面模式的更多相关文章
- 读书笔记之 - javascript 设计模式 - 代理模式
代理(proxy)是一个对象,它可以用来控制对另一对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替本体被实例化,并使其可被远程访 ...
- 读书笔记之 - javascript 设计模式 - 命令模式
本章研究的是一种封装方法调用的方式.命令模式与普通函数有所不同.它可以用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行. 它也可以用来消除调用操作的对象和实现操作的 ...
- 读书笔记之 - javascript 设计模式 - 单体模式
单体是一个用来划分命名空间,并将一批相关方法和属性组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次. 单体模式,就是将代码组织为一个逻辑单元,这个逻辑单元中的代码可以通过单一的变量进行访问 ...
- 读书笔记之 - javascript 设计模式 - 组合模式
组合模式是一种专为创建Web上的动态用户界面而量身定制的模式,使用这种模式,可以用一条命令在对各对象上激发复杂的或递归的行为. 在组合对象的层次体系中有俩种类型对象:叶对象和组合对象.这是一个递归定义 ...
- 读书笔记之 - javascript 设计模式 - 工厂模式
一个类或者对象中,往往会包含别的对象.在创建这种对象的时候,你可能习惯于使用常规方式,即用 new 关键字和类构造函数. 这会导致相关的俩个类之间产生依赖. 工厂模式,就是消除这俩个类之间的依赖性的一 ...
- 读书笔记之 - javascript 设计模式 - 适配器模式
适配器模式可以用来在现在接口和不兼容的类之间进行适配. 使用这种模式的对象又叫包装器,因为他们是在用一个新接口包装另一个对象. 在设计类的时候往往遇到有些接口不能与现有api一同使用的情况,借助于适配 ...
- JavaScript设计模式--门面模式
外部与一个子系统的通信必须通过一个系统的一个门面对象进行,这就是门面模式. 门面模式具备如下两个角色: 1. 门面角色 客户端可以调用这个角色方法,此角色中有子系统的应用(知晓相关的(一个或多个)子系 ...
- 读书笔记之 - javascript 设计模式 - 享元模式
本章探讨另一种优化模式-享元模式,它最适合于解决因创建大量类似对象而累及性能的问题.这种模式在javascript中尤其有用,因为复杂的javascript代码很快就会用光浏览器的所有可用内存,通过把 ...
- 读书笔记之 - javascript 设计模式 - 责任链模式
责任链模式可以用来消除请求的发送者和接收者之间的耦合.这是通过实现一个由隐式地对请求进行处理的对象组成的链而做到的.链中的每个对象可以处理请求,也可以将其传给下一个对象. 责任链的结构: 责任链由多个 ...
随机推荐
- Cubieboard编译安装NodeJS经验总结
Cubieboard编译安装NodeJS经验总结,以供新手免走弯路. Cubieboad用的是arm处理器,NodeJs的编译安装上不像pc上那么简单,可以一遍过. 单单make编译一次,就得几乎一个 ...
- JavaScript高级程序设计40.pdf
DOM0级事件处理程序 就是将一个函数赋值给一个事件处理程序属性,具有简单.跨浏览器优势,首先必须取得一个操作对象的引用,每个元素(包括window和document)都有自己的事件处理程序属性,这些 ...
- [Unix.C]Files and Directories
stat, fstat, and lstat Functions 本部分讨论的内容主要围绕3个stat函数及其返回值. #include <sys/stat.h> int stat(co ...
- zabbix邮件告警
Zabbix邮件告警看了很多文档,写的那叫一个蛋疼,明明没有发出去邮件,硬要糊弄观众,我也跟着被糊弄. 操作系统环境: CentOS 5.5 x84_64位 Zabbix版本2.2.3 Web服务器: ...
- 为什么用 Java:一个 Python 程序员告诉你
这篇文章专门给程序员写的,普通读者慎入.原作者:Kevin Sookocheff 译者:Celia Zhen,原文点击文末链接. 每当我告诉别人我一直在用Java工作时,大家的反应都是: “纳尼!Ja ...
- 如何运用同余定理求余数【hdoj 1212 Big Number【大数求余数】】
Big Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- 解决SDK下载时速度过慢的问题
1.打开android sdk manager 2.打开tool->options,如图所示 3.将Proxy Settings 里的HTTP Proxy Server和HTTP Proxy P ...
- 【设计模式 - 21】之空对象模式(Null Object)
1 模式简介 在空对象模式中,一个空对象取代NULL对象的实例的检查.NULL对象不是检查空值,而是反映一个不做任何动作的关系.这样的NULL对象也可以在数据不可用的时候提供默认的行为. 在 ...
- C#使用Sockets操作FTP【转载】
using System; using System.Collections; using System.IO; using System.Net; using System.Net.Sockets; ...
- Linux下top订购具体解释
Linux下top订购具体解释 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvempmMjgwNDQxNTg5/font/5a6L5L2T/fontsize ...