DOJO中的面向对象__第三章补充:关于preamble、postscript以及chain

  这是dojo.declare中的三个极度蛋疼的功能,在对多继承的实质有所了解之后,才会加深对这三个功能的认识,所以放到最后说。这里就不谈它们的实现原理了,第四章中也许会描述到= =!

 

  如果觉得运行constructor前后缺少了些什么,那么preamble、postscript可以很好的帮助我们进行弥补。根据我时间不长的开发经验,还想不出什么情况下需要这种操作来弥补。如果在类型的定义中包含了preamble方法,那么在这个类型的构造函数被调用之前,会首先执行一次preamble。同样如果定义了postscript方法,那么该类型的构造函数被调用之后,也会自动执行一遍postscript。下面是一个简单的例子:

dojo.declare('A',null,{
	preamble:function(){ console.log('A'); },	
	constructor:function(){ console.log('AA'); },
	postscript:function(){ console.log('AAA'); }
});
var a= new A();
/*输出:
A
AA
AAA
*/
 

  至于preamble和postscript方法究竟是如何被调用的,第四章中有解释,暂时不需要关注,可以认为这是Dojo提供好的机制。来个复杂一些的例子:

dojo.declare('A',null,{
	preamble:function(){ console.log('A'); },	
	constructor:function(){ console.log('AA'); },
	postscript:function(){ console.log('AAA'); }
});
dojo.declare('B',A,{	
	preamble:function(){ console.log('B'); },	
	constructor:function(){ console.log('BB'); },
	postscript:function(){ console.log('BBB'); }
});
dojo.declare('C',B,{	
	preamble:function(){ console.log('C'); },	
	constructor:function(){ console.log('CC'); },
	postscript:function(){ console.log('CCC'); }
});
var c= new C();
/* 输出:
C
B
A
AA
BB
CC
CCC
*/
 

  从输出的结果来看,我们可以挖掘出一些有意思的事情。在这种拥有继承的情况下,父类中postscript方法是不会被自动调用到的。上述例子的准确函数执行顺序是:

写道
1. C.preamble
2. B.preamble
3. A.preamble
4. A.constructor
5. B.constructor
6. C.constructor
7. C.postscript
 

  至于为什么不会调用到A和B的postscript方法,从Dojo的源码实现上讲是因为这里所调用的父类型的constructor并没有去执行postscript方法。换个角度说,这里调用父类型的constructor函数完成的构造过程,与我们直接通过new来调用的父类型发生的构造,是两回事。归纳来说,对类型L(A)= AA1A2A3…AN使用new进行实例化时,默认的执行顺序是:

写道
A.preamble-> A1.preamble-> A2.preamble ... AN.preamble->
AN.constructor-> AN-1.constructor ... A.constructor->
A.postscript
 

  在Dojo1.4之后的版本中,preamble已经被标记为deprecated函数,不过postscript并没有被列入deprecated。chain提供了自动执行父类中函数的功能。默认情况下,只有父类的构造函数是会被自动调用的,并且总是先于子类的构造函数执行。只有在一些特殊情况下,我们会需要让其他的函数也能够像构造函数一样,自动执行,免去我们手工调用的麻烦。举例来说,如果创建的类型包含了destroy函数,该函数会进行一些垃圾回收方面的工作,我们肯定希望destroy函数完成后也会自动去执行一下父类中的destroy。


  下面的例子定义了一条destroy函数组成的chain。其中的允许我们来设置函数的执行顺序,这里指定的是before顺序,也就是说子类的函数会先于父类的函数执行,所以子类的destroy先运行。

dojo.declare('A',null,{	
	constructor:function(){ console.log('A'); },
	destroy:function(){console.log('AA');}
});
dojo.declare('B',A,{	 
	constructor:function(){ console.log('B'); },
	destroy:function(){console.log('BB');}
});

dojo.declare('C',B,{	
	"-chains-": {
    		destroy: "before"
  	},
	constructor:function(){ console.log('C'); },
	destroy:function(){console.log('CC');}
});

var c= new C();
c.destroy();
/*输出:
A
B
C
CC
BB
AA
*/
 

有两点值得注意:


  第一点是"-chains-"语句所处的位置,上例中放在了C类型的定义中。如果放在A或者B类中,执行c.destroy()的效果还是一样的。事实上,只要把chain声明放在继承链条中的任何一个类型定义里,都可以达到串连所有同名函数的效果。对于复杂的多重继承结构也是这样的,因为他们实质上最终还是一条单继承结构。


  第二点是chain中允许我们声明三种类型的顺序,他们能够产生效果的对象不同。字面上,我们能够使用的是after\before\manual这三个顺序,他们分别代表了在父类函数执行之后执行、在父类函数执行之前执行、手动调用。对于非构造函数,设置manual是没有意义的,如果不是after顺序,会被一概视为before。而对于构造函数,设置before是没有意义的,因为父类的构造函数要么manual手动调用,要么一定会在子类的构造函数之前执行。

dojo.declare('A',null,{	
 	"-chains-": {
    		constructor: "before",	//没有作用,非‘manual’即被视为‘after’
    		foo: "manual"				//没有作用,非‘after’即被视为‘before’
  	},
	constructor:function(){ console.log('A'); },
	foo:function(){console.log('AA');}
});
dojo.declare('B',A,{	
	constructor:function(){ console.log('B'); },
	foo:function(){console.log('BB');}
});
dojo.declare('C',B,{	
	constructor:function(){ console.log('C'); },
	foo:function(){console.log('CC');}
});
var c= new C();
c.destroy();
/*输出:
A
B
C
CC
BB
AA
*/
 

  最后来看一个针对构造函数设置manual的例子。

dojo.declare('A',null,{
	"-chains-": { constructor: "manual" },
	constructor:function(){ console.log('A'); }
});
dojo.declare('B',A,{		
	constructor:function(){ console.log('B'); }
});
dojo.declare('C',B,{	
	constructor:function(){		
		this.inherited(arguments); //设置为manual后,只能手动调用父类函数
		console.log('C'); 
	}
});
var c= new C();
/*输出:
B
C
*/
 

  从这个例子可以看出,在设置了manual后,如果不手动去调用父类的构造函数,那么父类的构造函数是不会执行的,因此这里就不会打印A,根据第二章中的描述,手动调用可以使用inherited方法。

 

  PS,之前我以为preamble、postscript以及chain会在dijit中被较多使用到,但根据在Dojo1.5源码中的搜索,很不幸,只有postscript在dijit中被使用过,至于preamble和chain基本上在整个Dojo的实现代码中都没有,只有在test的代码里出现过两三次。可见这些功能偏门 到什么程度。我觉得API提供的原则应该是简单易用 ,而Dojo的接口往往体现着庞大复杂精深,我想这可能也是很多web fronter不愿意花成本去学习去使用的Dojo的原因吧。其实作为开发者来说,Dojo用熟了也并没有感觉太复杂,你甚至会为它的细致周全感到震撼,但是对于初学者来说,或者是那些急于上手某个Ajax框架进行开发的人,Dojo的确不是一个好的选择。

你可能感兴趣的:(C++,c,Ajax,C#,dojo)