读书人

扩充接口的思考

发布时间: 2012-11-01 11:11:31 作者: rapoo

扩展接口的思考
在设计MeteorTL时,
模板指令,表达式操作符的可扩展性,一直没有找到好的方案。
由于扩展是由第三方实现的,所以一般采用SPI(Service Provide Interface)接口的方式。
在留出SPI接口时,引擎需要传递编译期数据及运行时数据给扩展方,
运行时数据肯定是用callback函数的参数列表传递,
但编译期数据是其应持有的状态,所以必需在初始化时给予。
以指令为例:

Class ll = Class.forName("*.*.Directive");  Method init= ll.getDeclaredMethod("init",参数Class);//设置安全访问权限级别,允许访问私有方法init.setAccessible(true);t = init.invoke(指令实例,方法参数实例);
5 楼 leadyu 2007-06-29 就是说,引擎能够提供什么数据给指令都是由引擎调用指令的私有init方法传递给指令的实现类,实现类自己有什么其他属性需要构造由它自己来定,不是很明白为什么要newInstance来实例一个指令? 6 楼 leadyu 2007-06-29 指令也应该是一个抽象类,指令肯定会涉及到一些内在行为需要约束,而不是由扩展者随意实现,有了访问私有方法的办法,应该可以解决约束性和封装性,就像你第二个方案提出的矛盾是可以很好解决的,看看jdk的很多模型的实现基本都采用这种方式。 7 楼 leadyu 2007-06-30 纠正一个笔误,应该init方法要改成protected,否则估计子类通过反射会找不到这个方法,呵呵 8 楼 javatar 2007-07-02 leadyu 写道不是很明白为什么要newInstance来实例一个指令?

问题就是你下面一句:

leadyu 写道t = init.invoke(指令实例,方法参数实例);

这里“指令实例”从哪里来?

而且这个指令实例是每个节点需要新的实例,
如:
@if{xxx}
...@if{yyy}
......
...@end
@end
这里的if指令就有两个实例。

所以指令实例的创建就由引擎负责,
最简单的办法就是Class.newInstance();

用Handler,所有指令可以共享同一Handler(其无状态性,保证单一实例可以在多线程下共享),
所以Handler可以由用户自己创建并传给引擎。
9 楼 leadyu 2007-07-02 呵呵,我只是针对你第二个回复中提出的契约性的矛盾提出一种新的思路而已。我理解你说的问题,一个是指令的逻辑,一个是runtime数据。引擎保存的是Handle实例,handle就代表逻辑,无状态,template代表runtime数据,所以你引擎保存的不是指令的实例。

另外,再请教javatar兄一个问题,你引擎在执行一个指令时,比如out,是一次性把整个template的所有out指令都执行完,还是按照template编写的指令顺序一个个执行?如果是后者,好像从接口没看出来,指令怎么识别自己的template的位置? 10 楼 leadyu 2007-07-02 另外,建议,指令的handle接口没有定义方法,只是一个标志接口,在另外写多几个子接口各自定义方法,毕竟不同类型的指令,可能需要不同的执行接口,不一定是统一的。 11 楼 leadyu 2007-07-02 ?引用另外,再请教javatar兄一个问题,你引擎在执行一个指令时,比如out,是一次性把整个template的所有out指令都执行完,还是按照template编写的指令顺序一个个执行?如果是后者,好像从接口没看出来,指令怎么识别自己的template的位置?


你是不是把所有的静态文本都编译成Out指令?执行过程中不断往输出写 12 楼 javatar 2007-07-03 指令的总体结构是设计成解释器模式的。

指令集被引擎编译成树(合成模式):
Directive和BlockDirective, BlockDirective继承于Directive,
BlockDirective比Directive多一个List<Directive> getInnerDirectives();
Template引用树的根指令,按解释器模式的方式层级调用。

leadyu 写道你是不是把所有的静态文本都编译成Out指令?执行过程中不断往输出写

是的,静态文本被编译成TextDirective,此指令总是输出其持有的固定文本。TextDirective是包保护级的,不对外公开。

读书人网 >软件架构设计

热点推荐