首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

DOJO中的面向对象_第三章 Dojo中的多沿袭

2012-11-23 
DOJO中的面向对象__第三章 Dojo中的多继承(一) 定义多继承  Dojo在基于类的面向对象系统方面增强了JS的表

DOJO中的面向对象__第三章 Dojo中的多继承
(一) 定义多继承

  Dojo在基于类的面向对象系统方面增强了JS的表现力,在第二章中已经提到Dojo还允许用户使用多继承,本章将主要探讨关于多继承的内容。利用dojo.declare声明多继承的类是很方便的,用户只需要传递一个数组(superclass)进去,superclass数组包含了所有的父类。

?

  该例声明了类型A、B、C、D,注意在声明类D的时候传入了superclass数组——[A, B, C],这使得D成为A、B、C的子类。运行上面代码会首先打印A,在执行A的构造器之后,其他基类的构造器也会按传入顺序被执行,D的构造器会被最终调用。同时,D也继承了A、B、C三个父类中其他域。

?

  事实上,A是D的唯一一个真正的父类,这是由于Dojo在实现多继承的时候,仅仅将A采纳为D的父类,其他的‘父类’仅仅会被mixin进A(具体细节可以参考第三章第四小节)。但抛开实现的细节来看,用户真正需要得到的结果是D是A、B、C这三个类的子类。因此,这时候采用JS中的instanceof运算符并不能很好的判断类型。拿上例来说:

  面向对象语言如果支持了多继承的话,都会遇到著名的菱形问题(Diamond Problem)。假设存在一个如左图所示的继承关系,O中有一个方法foo,被A类和B类覆写,但是没有被C类覆写。那么C在调用foo方法的时候,究竟是调用A中的foo,还是调用B中的foo?


  不同语言对这个问题的处理方式有所不同。例如C++中采用虚继承,而Python中采用MRO的方式来解决。MRO又称作方法解析顺序(Method Resolution Order),即查找被调用的方法所在类时的搜索顺序。在Python中一共出现过三种MRO,Dojo中采纳了Python2.3版本之后的MRO算法,该算法简称C3算法。

?

  C3算法简单来说是将一个类型以及它的所有父类进行线性化排列。之所以进行线性排列,其实是想让这些类按照某种重要程度排序,然后实际调用方法的时候,在这个线性序列中从前向后依次寻找,最靠前的方法才会被调用到。比如上面图片中的这个例子,在Python中可以描述为:

这里有四层继承结构。我们从上到下逐层计算线性化序列:

?

对该继承结构计算线性化序列:

?

  下面举例来具体说明Dojo与Python中MRO的区别。假设有如左图所示的继承,分别计算MRO顺序:

?

DOJO中的面向对象_第三章 Dojo中的多沿袭

?

  通过上述的例子可以发现,由于merge中传入参数的顺序不同,导致最终得出的MRO顺序不同。整体上Python倾向于一种类似广度优先搜索的顺序,而Dojo中的结果呈现出一种深度优先的搜索顺序,不过实际上并不是很准确。

?

  除了在整体上反映出不同的优先顺序,Dojo中的MRO做法实际上避免了许多MRO失败。在上一小节已经描述过一种情况,由于父类均是从同样的类型继承而来,但是继承的顺序不同,导致子类无法确定优先级关系,因此merge步骤失败。还有一种情况是,如果父类之间彼此也存在继承关系,那么同样会容易导致MRO失败,比如说下面所示的继承。

?

DOJO中的面向对象_第三章 Dojo中的多沿袭

  如上图所示,C类的两个父类A和B之间发生了继承关系。在Python的MRO中,右边的一个继承关系是失败的。利用C3算法可以很快的推导出来。

?

  在Dojo中左边的继承能够MRO成功,主要原因是merge时传入的参数比Python中少了父类型序列。如下所示:

?

  利用dojo.declare声明的时候,只有一个类被当作父类,其余所有传入的类仅仅做mixin用。通常是superclass中的第一个类会被当做父类,即对于继承C(B1 ... BN),B1会被当做C的父类,不过这是有前提的,即L(C)的末尾完全由L(B1)构成。大部分情况下,这个前提都是可以满足的,但是也有不满足的情况,这时候所选取的父类就是L(C)中的最后一个类。举例来说:

DOJO中的面向对象_第三章 Dojo中的多沿袭

?

  可以用JS提供的instanceof来判断是否是父类型的实例。而针对其他mixin的类型使用,则会失败,这时候可以用第二章中描述过的isInstanceOf函数。例如,对于上面的例一:

var f = new F();console.log(f instanceof A );//falseconsole.log(f.isInstanceOf(A)); //trueconsole.log(f instanceof B ); //falseconsole.log(f instanceof C ); //falseconsole.log(f instanceof E ); //falseconsole.log(f instanceof F ); //trueconsole.log(f instanceof D ); //true
?

  根据L(F)= FECBAD可以看出,类型F处于继承结构的最底端,而类型D是F的父类,处于最顶端。这两个类型都能够直接被instanceof识别,其余的ABCE都只能利用Dojo提供的isInstanceOf才能返回true。

?

?

?

?

?

?

?

?

热点排行