基于“甘露模型”的多重继承和接口实现,附带“准”桥接模式的验证
看了李战师兄的《悟透javascript》,受益非浅。基于甘露模型的基础上,我稍微做了些修改,支持了多重继承和接口(浏览器、ASP-jscript和jscript.net三种环境下调试通过)。
关于多重继承,也许会有些朋友存在意见,而我的观点是,用与不用和用得好用得坏,是人的问题,而不是编译器的问题。
在接口的继承上,函数Class会自动查找当前类是否已经实现了接口的方法,如果没有实现,则会抛出错误,终止执行,这也相当于尽量接近了C#的:
class 某某某:接口1,接口2,接口3
{
//------------------------
}
在最后面,通过一个桥接模式,来验证这些功能。
难免会有疏漏,还请大家指明。
再次感谢李战师兄的点化。
Function.Amethod = null;
function Class() //创建类的函数,用于声明类及继承关系
{
var args =Class.arguments; //获取参数集合
function class_() //创建类的临时函数壳
{
this.Type = args[0]; //我们给每一个类约定一个Type属性,引用其继承的类
try
{
for (var i = 0; i < args.length; i++)
{
for (var member in args[i])
{
if (args[i][member] != Function.Amethod)
{
this[member] = args[i][member]; //复制类的全部定义到当前创建的类
}
else
{
//如果检测到这是一个虚函数,则判断继承链中存在接口。
//检测当前类是否已经实现了接口的方法
if (!args[args.length - 1][member]) {
throw ("错误信息:未实现" + member);
return false;
}
}
}
}
}
catch (err) {
/*
Response.Write(err); //在asp和asp.net中
Response.End();
*/
window.alert(err); //在浏览器中
}
};
return new class_();
}
var Interface = function(method) {
function temp() {
for (var a in method) {
this[a] = Function.Amethod;
}
}
return new temp();
}
function New(aClass, aParams) //创建对象的函数,用于任意类的对象创建
{
function new_() //创建对象的临时函数壳
{
this.Type = aClass; //我们也给每一个对象约定一个Type属性,据此可以访问到对象所属的类
if (aClass.Create)
aClass.Create.apply(this, aParams); //我们约定所有类的构造函数都叫Create,这和DELPHI比较相似
};
new_.prototype = aClass;
return new new_();
}
在下面的服务器端应用执行时,需要把上面的甘露模型代码中的window.alert(err);一句注释掉,并开启原来已经注释的Response.Write
通过以上的两个例子,虽然我们在代码层面和执行层面上都实现了接口,但是回过头来说,Javascript语言本身就属于动态语言,它的变量声明是可以指向任何对象的,var a = 1; var a = "text"; var a = new Array(); 都是正确的,这也就说明了javascript本身就内置了“多态性”,似乎我们再构造一个接口就显得有些多余了。
其实不然,接口在强类型语言中除了在多态性应用上起到至关作用外,还有另一个特征:“你必须实现某某某方法!”,这在大型程序的开发上显得至关重要。或许我们会说javascript谈不上开发大型程序,但是要注意到,哪怕是一个小组件,连续不断地升级和修改都是常见的,两个月前写的代码,很难保证两个月后自己还能看得懂多少。此时如果在代码中出现接口继承,多多少少可以起到一个提示的作用:“想起来了,原来是这么回事。”,另一种情况:在其它程序员基于你的组件库平台之上开发新的应用时,你也只需要告诉他:“你继承这个接口就行了,它会自动帮你验证的”。
至于多重继承,办法很简单,不再多说了,给个例子:
var p1 = Class({pp1:"pp1"});
var p2 = Class({pp2:"pp2"});
var p3 = Class({pp3:"pp3"});
var xxx = Class(p1,p2,p3,{/* 当前类主体定义 */});