javascript语言不像java、 c#、 c++等面向对象语言那样有完备的接口支持,在javascript中,接口的实现有三种方式,分别为注释描述、属性检查、鸭式变形。注释描述实现起来最为简单,但是,接口约定的遵守纯靠自觉,而且也没有很好的度量措施,说到底,它主要还是属于程序文档范畴。其实,类是否申明自己支持哪些接口并不重要,只要它具有这些接口中的方法就行了。鸭式变形(这个名称来自James Whitcomb Riley的名言:"像鸭子一样嘎嘎叫的就是鸭子")正式基于这种认识。

  下面来谈谈javascript中接口的具体实现策略。(基于鸭式变形,用的也是最多的哦~~)

 * 接口类构造函数,接受2个以上的参数,其中第一个参数为接口名,后面的参数可以为字符串数组,也可以为字符串
* @param {Object} name
* 接口名
* @param {Object} methods
* 接口包含的方法集合,参数可以为数组,也可以传入任意多的字符串形式的方法名
*/
var Interface = function(name, methods){
if(arguments.length < 2){ //若参数个数不为2,则抛出错误
throw new Error("Interface constructor called with" + arguments.length +
"arguments, but expected at least 2");
} this.name = name;
this.methods = []; for(var i = 1, len = arguments.length; i < len; ++i){
if(arguments[i] instanceof Array){ //若参数为数组,则遍历该参数
for(var j = arguments[i].length - 1; j > -1; --j){
if(typeof arguments[i][j] !== 'string' ){//保证传入的方法名为字符串,否则抛出错误
throw new Error('Interface constructor expects method names to be passed in as a string');
} this.methods.push(arguments[i][j]); //保存方法名
}
} else if(typeof arguments[i] === 'string'){ //参数为字符串,直接保存
this.methods.push(arguments[i]);
} else { //否则抛出错误
throw new Error('Interface constructor expects method names to be passed in as a string');
}
}
}; /*
* 接口实现检验函数,第一个参数为要检查的对象,后面的任意参数为实现的接口对象,也可以为接口对象数组
* @param {Object} object
*/
Interface.ensureImplents = function(object){
if(arguments.length < 2){
throw new Error("Interface constructor called with" + arguments.length +
"arguments, but expected at least 2");
} var _checkMethods = function(inface){ //内部函数,用于检验对象是否实现了ifs对象中的方法
var methods = inface.methods,
i = methods.length - 1; for( ; i > -1; --i){
var method = methods[i];
//若对象不存在该属性,或者该属性不是方法,那么抛出错误
if(typeof object[method] === 'undefined' || typeof object[method] !== 'function'){
throw new Error("Function Interface.ensureImplents: object does not implent the " +
inface.name + "interface. Method " + method + " was not found." );
}
}
}; for (var i = arguments.length - 1; i > 0; --i) {
if(arguments[i] instanceof Array){
for(var j = arguments[i].length - 1; j > -1; --j){
if(!arguments[i][j] instanceof Interface){
throw new Error('Function Interface.ensureImplents expects arguments two and above to be' +
'instances of Interface');
}
_checkMethods(arguments[i][j]); //检验接口实现
}
} else if(arguments[i] instanceof Interface){
_checkMethods(arguments[i]); //检验接口实现
} else {
throw new Error('Function Interface.ensureImplents expects arguments two and above to be' +
'instances of Interface');
}
}
};
  编写出上述代码挺简单,主要思路就是检测传入参数的类型和名称。看看某个具体实现类有没有实现所定义的接口中的那些function。。
  下面给出一个调用接口的例子吧~
//2个接口实例
var ITest = new Interface('ITest', 'test0', ['test1', 'test2'], 'test3');
var ISay = new Interface('ISay', 'say0', 'say1');
//未继承的任何对象,仅是实现了ITest接口
var implentTest = {
test0: function(){
alert('test0');
},
test1:function(){
alert('test1');
},
test2:function(){
alert('test2');
},
test3:function(){
alert('test3');
}
} var implentSay = {
say1:function(){
alert('say1');
},
say0:function(){
alert('say0');
}
}; function TestAndSay (){
this.say0 = function(){
alert('test0 and say0');
}; this.say1 = function(){
alert('tes1t and say1');
};
} TestAndSay.prototype = implentTest; //一个简单的继承 var implentTestAndSay = new TestAndSay(); //实例化 function test(ITestInstance){
Interface.ensureImplents(ITestInstance, ITest);
ITestInstance.test0();
ITestInstance.test1();
ITestInstance.test2();
} function say(ISayInstance){
Interface.ensureImplents(ISayInstance, ISay);
ISayInstance.say0();
ISayInstance.say1();
} function sayAndtest(inst){
Interface.ensureImplents(inst, ISay, ITest);
inst.test0();
inst.say0();
inst.say1();
} test(implentTest);//弹出3个对话框:test0 test1 test2
//test(implentSay);将会抛出错误
//say(implentTest); 将会抛出错误
say(implentSay);//弹出2个对话框 say0 say1
sayAndtest(implentTestAndSay); //弹出3个对话框: test0; test0 and say0; test1 and say1

  哈哈,有了接口的定义及实现后,你就可以在设计模式中充分发挥你的才能了,让设计模式为我们服务吧!

javascript设计模式开篇:Javascript 接口的实现的更多相关文章

  1. JavaScript设计模式 Item 2 -- 接口的实现

    1.接口概述 1.什么是接口? 接口是提供了一种用以说明一个对象应该具有哪些方法的手段.尽管它可以表明这些方法的语义,但它并不规定这些方法应该如何实现. 2. 接口之利 促进代码的重用. 接口可以告诉 ...

  2. JavaScript设计模式之一Interface接口

    如何用面向对象的思想来写JavaScript,对于初学者应该是比较难的,我们经常用的JQuery其实也是用面向对象的思想去封装的,今天我们来看看如何在Javascript中用Interface,在C# ...

  3. Javascript设计模式笔记

    Javascript是越来越厉害了,一统前后端开发.于是最近把设计模式又看了一遍,顺便做了个笔记,以方便自己和他人共同学习. 笔记连载详见:http://www.meteorcn.net/wordpr ...

  4. 【JavaScript设计模式系列---开篇预览】

    转:http://www.cnblogs.com/Darren_code/archive/2011/08/31/JavascripDesignPatterns.html 2011-08-31 23:5 ...

  5. 《javascript设计模式》--接口

    关于javascript设计模式书中的接口,记录如下 //TODO  增加了一个判断条件,可以只在生产环境中调用 接口var Interface = function(name,methods){ i ...

  6. 21种JavaScript设计模式最新记录(含图和示例)

    最近观看了<Javascript设计模式系统讲解与应用>教程,对设计模式有了新的认识,特在此做些记录. 一.UML 文中会涉及众多的UML类图,在开篇需要做点基础概念的认识.以下面的图为例 ...

  7. 《JavaScript设计模式 张》整理

    最近在研读另外一本关于设计模式的书<JavaScript设计模式>,这本书中描述了更多的设计模式. 一.创建型设计模式 包括简单工厂.工厂方法.抽象工厂.建造者.原型和单例模式. 1)简单 ...

  8. 《JavaScript设计模式与开发实践》整理

    最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...

  9. 常用的Javascript设计模式

    <parctical common lisp>的作者曾说,如果你需要一种模式,那一定是哪里出了问题.他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案. 不管是弱类型 ...

随机推荐

  1. c++日志记录模块

    C++ 日志记录模块 该模块从实际项目中产生,通过extern声明的方式,可在代码不同模块中生成日志,日志文件名称为随机码加用户指定名称,采用随机码是为了避免日志文件可能被覆盖的问题. 愿意的话你也能 ...

  2. 智能合约bug以及修改方案

    截取两篇文章:第一遍文章说的是智能合约能不能修改的问题: ETC转到ETH地址以及转币进ETH智能合约账户能不能转出来? 第0章 引言 如果ETC充值到了ETH地址上,能找回来吗?答案是不一定. ET ...

  3. MyBatis3-动态SQL语句

    MyBatis的动态SQL语句是基于OGNL表达式的.可以方便的在SQL语句中实现某些逻辑,总体说来MyBatis动态SQL语句主要有以下几类: 1.if语句(简单的条件判断). 2.choose(w ...

  4. mysql select 字段别名是否可以用在 select中或者where中

    select column1+10 as c1,c1+10 as c2 from table1;想实现上面的效果,结果在mysql里面报错了,提示找不到c1这个列; -- 不同的 数据库不一样 一般不 ...

  5. kafka学习总结之kafka简介

    kafka是一个分布式,基于subscribe-publish的消息系统 特性:高吞吐量.低延迟.可扩展性.持久性(消息持久化到本地磁盘).可靠性.容错性(n个副本,允许n-1个节点失败).高并发(支 ...

  6. 《LINUX内核设计与实现》第三周读书笔记——第一二章

    <Linux内核设计与实现>读书笔记--第一二章 20135301张忻 估算学习时间:共2小时 读书:1.5 代码:0 作业:0 博客:0.5 实际学习时间:共2.5小时 读书:2.0 代 ...

  7. Linux内核分析——第五周学习笔记

    第五周 扒开系统调用的“三层皮”(下) 一.知识点总结 (一)给MenuOS增加time和time-asm命令 在实验楼中,首先 强制删除menu (rm menu -rf) 重新克隆一个新版本的me ...

  8. 作业六:分析Linux内核创建一个新进程的过程

    分析Linux内核创建一个新进程的过程 进程描述符PCB----task_struct数据结构 操作系统:1.进程管理 2.内存管理 3 文件系统 一.新进程如何创建和修改task_struct数据结 ...

  9. ES6 数值的扩展

    在ES5中,我们存在几个全局函数 isNaN函数,isFinite函数,parseInt函数,parseFloat函数等,对于这些全局函数的使用很简单,就拿isNaN函数来举例. ES5中的写法是: ...

  10. C语言变长数组data[0]

    1.前言 在刷题时遇到一个结构中包含char data[0],第一次见到时感觉很奇怪,数组的长度怎么可以为零呢?于是上网搜索一下这样的用法的目的,发现在linux内核中,结构体中经常用到data[0] ...