javascript设计模式开篇:Javascript 接口的实现

  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

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

posted @ 2014-05-27 11:04  地狱火之歌  阅读(238)  评论(0编辑  收藏  举报