javascript设计模式 接口介绍


Posted in Javascript onJuly 24, 2012

这本书中第一个重要的内容就是接口。

大家对接口应该都不陌生,简单的说接口就是一个契约或者规范。在强类型的面相对象语言中,接口可以很容易的实现。但是在javascript中并没有原生的创建或者实现接口的方式,或者判定一个类型是否实现了某个接口,我们只能利用js的灵活性的特点,模拟接口。
在javascript中实现接口有三种方式:注释描述、属性验证、鸭子模型。
note:因为我看的是英文书,翻译水平有限,不知道有些词汇如何翻译,大家只能领会精神了。
1. 注释描述 (Describing Interfaces with Comments)
例子:

/* 
interface Composite { 
function add(child); 

function remove(child); 

function getChild(index); 
} 
interface FormItem { 

function save(); 
} 
*/ 
var CompositeForm = function(id, method, action) { // implements Composite, FormItem 

... 
}; 
//Implement the Composite interface. 
CompositeForm.prototype.add = function(child) { 
... 
}; 
CompositeForm.prototype.remove = function(child) { 
... 
}; 
CompositeForm.prototype.getChild = function(index) { 
... 
}; 
// Implement the FormItem interface. 
CompositeForm.prototype.save = function() { 
... 
};

模拟其他面向对象语言,使用interface 和 implements关键字,但是需要将他们注释起来,这样就不会有语法错误。
这样做的目的,只是为了告诉其他编程人员,这些类需要实现什么方法,需要在编程的时候加以注意。但是没有提供一种验证方式,这些类是否正确实现了这些接口中的方法,这种方式就是一种文档化的作法。
2. 属性验证(Emulating Interfaces with Attribute Checking)
例子:
/* interface 
Composite { 
function add(child); 
function remove(child); 
function getChild(index); 
} 
interface FormItem { 
function save(); 
} 
*/ 
var CompositeForm = function(id, method, action) { 
this.implementsInterfaces = ['Composite', 'FormItem']; 
... 
}; 
... 
function addForm(formInstance) { 
if(!implements(formInstance, 'Composite', 'FormItem')) { 

throw new Error("Object does not implement a required interface."); 

} 

... 
} 
// The implements function, which checks to see if an object declares that it 
// implements the required interfaces. 
function implements(object) { 

for(var i = 1; i < arguments.length; i++) { 


// Looping through all arguments 


// after the first one. 


var interfaceName = arguments[i]; 


var interfaceFound = false; 


for(var j = 0; j < object.implementsInterfaces.length; j++) { 



if(object.implementsInterfaces[j] == interfaceName) { 




interfaceFound = true; 




break; 



} 


} 


if(!interfaceFound) { 



return false; 



// An interface was not found. 

 } 

} 

return true; 
// All interfaces were found. 
}

这种方式比第一种方式有所改进,接口的定义仍然以注释的方式实现,但是添加了验证方法,判断一个类型是否实现了某个接口。
3.鸭子类型(Emulating Interfaces with Duck Typing)
// Interfaces. 
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']); 
var FormItem = new Interface('FormItem', ['save']); 
// CompositeForm class 
var CompositeForm = function(id, method, action) { 
... 
}; 
... 
function addForm(formInstance) { 

ensureImplements(formInstance, Composite, FormItem); 

// This function will throw an error if a required method is not implemented. 

... 
} 
// Constructor. 
var Interface = function(name, methods) { 

if(arguments.length != 2) { 


throw new Error("Interface constructor called with " 






 + arguments.length + "arguments, but expected exactly 2."); 

} 

this.name = name; 

this.methods = []; 

for(var i = 0, len = methods.length; i < len; i++) { 


if(typeof methods[i] !== 'string') { 



throw new Error("Interface constructor expects method names to be " 







+ "passed in as a string."); 


} 


this.methods.push(methods[i]); 

} 
}; 
// Static class method. 
Interface.ensureImplements = function(object) { 

if(arguments.length < 2) { 


throw new Error("Function Interface.ensureImplements called with " 







+arguments.length + "arguments, but expected at least 2."); 

} 
for(var i = 1, len = arguments.length; i < len; i++) { 


var interface = arguments[i]; 


if(interface.constructor !== Interface) { 



throw new Error("Function Interface.ensureImplements expects arguments" 







+ "two and above to be instances of Interface."); 


} 


for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) { 



var method = interface.methods[j]; 



if(!object[method] || typeof object[method] !== 'function') { 




throw new Error("Function Interface.ensureImplements: object " 








+ "does not implement the " + interface.name + " interface. Method " + method + " was not found."); 



} 


} 

} 
};

何时使用接口?
一直使用严格的类型验证并不适合,因为大多数javascript程序员已经在没有接口和接口验证的情况下编程多年。当你用设计模式开始设计一个很复杂的系统的时候,使用接口更有益处。看起来使用接口好像限制了javascript的灵活性,但实际上他让你的代码变得更加的松耦合。他使你的代码变得更加灵活,你可以传送任何类型的变量,并且保证他有你想要的方法。有很多场景接口非常适合使用。
在一个大型系统里,很多程序员一起参与开发项目,接口就变得非常必要了。程序员经常要访问一个还没有实现的api,或者为其他程序员提供别人依赖的一个方法存根,在这种情况下,接口变得相当的有价值。他们可以文档化api,并作为编程的契约。当存根被实现的api替换的时候你能立即知道,如果在开发过程中api有所变动,他能被另一个实现该接口的方法无缝替换。
如何使用接口?
首先要解决的问题是,在你的代码中是否适合使用接口。如果是小项目,使用接口会增加代码的复杂度。所以你要确定使用接口的情况下,是否是益处大于弊端。如果要使用接口,下面有几条建议:
1.引用Interface 类到你的页面文件。interface的源文件你可以再如下站点找到: http://jsdesignpatterns.com/.
2.检查你的代码,确定哪些方法需要抽象到接口里面。
3.创建接口对象,没个接口对象里面包含一组相关的方法。
4.移除所有构造器验证,我们将使用第三种接口实现方式,也就是鸭子类型。
5.用Interface.ensureImplements替代构造器验证。
Javascript 相关文章推荐
js 调用父窗口的具体实现代码
Jul 15 Javascript
高效率JavaScript编写技巧整理
Aug 23 Javascript
为开发者准备的10款最好的jQuery日历插件
Feb 04 Javascript
JQuery中节点遍历方法实例
May 18 Javascript
JavaScript取得WEB安全颜色列表的方法
Jul 14 Javascript
javascript实现base64 md5 sha1 密码加密
Sep 09 Javascript
微信小程序 http请求详细介绍
Oct 09 Javascript
angular实现form验证实例代码
Jan 17 Javascript
JS中的数组转变成JSON格式字符串的方法
May 09 Javascript
JavaScript数组push方法使用注意事项
Oct 30 Javascript
webpack中如何使用雪碧图的示例代码
Nov 11 Javascript
vue+elementUI(el-upload)图片压缩,默认同比例压缩操作
Aug 10 Javascript
javascript设计模式 封装和信息隐藏(上)
Jul 24 #Javascript
js+xml生成级联下拉框代码
Jul 24 #Javascript
40个新鲜出炉的jQuery 插件和免费教程[上]
Jul 24 #Javascript
基于jquery的跟随屏幕滚动代码
Jul 24 #Javascript
基于JQuery的类似新浪微博展示信息效果的代码
Jul 23 #Javascript
基于jquery自定义图片热区效果
Jul 21 #Javascript
Js四则运算函数代码
Jul 21 #Javascript
You might like
IStream与TStream之间的相互转换
2008/08/01 PHP
PHP中使用sleep造成mysql读取失败的案例和解决方法
2014/08/21 PHP
php+ajax实现无刷新分页的方法
2014/11/04 PHP
Yii2针对游客、用户防范规则和限制的解决方法分析
2016/10/08 PHP
php实现异步将远程链接上内容(图片或内容)写到本地的方法
2016/11/30 PHP
PHP实现针对日期,月数,天数,周数,小时,分,秒等的加减运算示例【基于strtotime】
2017/04/19 PHP
js实现运动logo图片效果及运动元素对象sportBox使用方法
2012/12/25 Javascript
JS操作图片(增,删,改) 例子
2013/04/17 Javascript
js中reverse函数的用法详解
2013/12/26 Javascript
jQuery 获取、设置HTML或TEXT内容的两种方法
2014/05/23 Javascript
JS/jQuery判断DOM节点是否存在的简单方法
2016/11/24 Javascript
vue2.0父子组件间通信的实现方法
2017/04/19 Javascript
Promise.all中对于reject的处理方法
2018/08/01 Javascript
vue+node实现图片上传及预览的示例方法
2018/11/22 Javascript
详解ES6中class的实现原理
2020/10/03 Javascript
详解微信小程序轨迹回放实现及遇到的坑
2021/02/02 Javascript
[01:31:02]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第一场
2019/08/22 DOTA
Python中的CURL PycURL使用例子
2014/06/01 Python
Python实现HTTP协议下的文件下载方法总结
2016/04/20 Python
Python基础教程之tcp socket编程详解及简单实例
2017/02/23 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
2017/11/11 Python
python 字典中文key处理,读取,比较方法
2018/07/06 Python
Python 实现OpenCV格式和PIL.Image格式互转
2020/01/09 Python
快速解释如何使用pandas的inplace参数的使用
2020/07/23 Python
基于python获取本地时间并转换时间戳和日期格式
2020/10/27 Python
html5使用canvas实现图片下载功能的示例代码
2017/08/26 HTML / CSS
Kenneth Cole官网:纽约时尚优雅品牌
2016/11/14 全球购物
一份Java笔试题
2012/02/21 面试题
营销与策划专业毕业生求职信
2013/11/01 职场文书
小学班长竞选演讲稿
2014/04/24 职场文书
我的小天地教学反思
2014/04/30 职场文书
离职感谢信
2015/01/21 职场文书
2015年社区党务工作总结
2015/04/21 职场文书
初中物理教学反思
2016/02/19 职场文书
Feign调用传输文件异常的解决
2021/06/24 Java/Android
gtx1650怎么样 gtx1650显卡相当于什么级别
2022/04/08 数码科技