再谈tapestry-delegate——优化与重构

来源:互联网 发布:python.ax.text 编辑:程序博客网 时间:2024/05/29 14:41

这段时间我对tapestry-delegate这个用于改进Tapestry 的"listener:"绑定的扩展开源包做了一次较大的调整和改进,使这个包在使用的灵活性和性能方面有了不少的提高。除了使用字节码生成技术来提高最终函数调用的效率外,还在多个候选函数的选择,类型的匹配,冗余函数的清理等方面做了改进。现在这个包可以支持如下几种使用的格式:

  • 模糊格式:"delegate:doSubmit"。这种格式下,所有以doSubmit命名的函数都会被作为候选的 delegate 函数。如果有多个函数与给定的 listener 参数拥有相同的参数个数(不包括第一个IRequestCycle参数),那么,当有事件触发时(比如提交页面或电击链接等),会自动搜索与所给 listener 参数(service 参数)最为接近的函数调用。对函数的搜索顺序和 "listener:"绑定搜索的顺序完全相同,以 "method(parameters)","method(IRequestCycle, parameters)","method()", "method(IRequestCycle)" 的顺序搜索。

  • 数字格式:"delegate:doSubmit(num)"。这种格式下可以给定候选 delegate 函数的参数个数(如果第一个是IRequestCycle,则不包括这个参数)。与模糊格式相同的是,如果有多个候选函数,那么会搜索一个与给定 listener 参数最为接近的函数调用。此时,只会按"method(parameters)","method(IRequestCycle, parameters)"的顺序搜索。

  • 精确格式:"delegate:doSubmit(types)"。这种格式下必须给出候选 delegate 函数的完整函数签名(如果第一个参数是IRequestCycle 也必须给出)。types(参数类型)可以是任意的,比如说原始类型,数组,接口或对象。你可以给出完整的类型名,也可以给出该类型的简称。你可以给出某个参数的参数名,也可以不给出。比如你可以说"delegate:doSubmit(java.lang.String)",你也可以给出"delegate:doSubmit(String s)"。当然,在极少的情况下,你有两个函数,他们的函数类型简称相同,那么在页面生成时就会报警提示你无法确定选择那一个函数。此时你就必须给出每个参数的具体类型加以区别。

    为了减少 delegate 函数生成的个数,语意上冗余的函数会被忽略。比如说你有两个函数"method()"和"method(IRequestCycle)",那么第二个函数会被忽略掉。因为按照给定的搜索顺序,第二个函数是不可能有机会被搜索到的。


    不论你选用哪一种格式,如果候选的函数只有一个(去掉冗余函数之后),那么调用的时候都会被直接调用而无须做任何的搜索。因此,无论在什么时候下精确格式肯定拥有最快的运行效率。


    数字格式,和模糊格式都有不同程度的灵活性。数字格式是模糊格式的一个特例,它只搜索给定参数个数的函数。模糊格式是最为灵活的,对于给定的 listener 参数,最合适这个参数的函数将会调用。比如说有A、B、C两个类,A是B的父类,C与A、B无关,你有三个函数函数 "method(A)"、"method(B)","method()"。如果此时参数类型为A,则调用 "mehtod(A)"。如果此时参数类型为B,则调用"method(B)"。如果此时参数类型为C,则调用"mehtod()"。值得注意的是,如果参数包含null值,语意上就有些模糊了,除了原始类型不能和它匹配外其它类型都可以和它匹配。 在这种情况下,第一个被找到的函数将会被调用。


    "listener:"绑定对于四种类型的监听函数使用了四个循环来查找,也就是说一个循环搜索一种类型(查找过程中的四种类型)。最坏的情况下就得有四个循环才能查找到需要的函数。"delegate:"在这方面也做了改进。首先,在生成时会对所有的候选函数使用一个公式算出的优先值进行排序。其次,使用一个byte数组记录对于每个函数不包括第一个为IRequestCycle情况下的参数个数。这样,一趟搜索就可以查处合适的函数集合,而且不再需要计算每个函数的参数个数。

公式:PRI = 2 * (parameterCount + 1) - (firstIsCycle ? 3 : 0);

    如果有四个函数 method(), method(IRquestCycle), method(int), method(IRequestCycle, int),则算出的优先数分别为2,1,4,3。按这个优先数排序可得 method(int),method(IRequetCycle, int),method(),method(IRequestCycle)。正好与搜索顺序相同(为了便于演示,此例没有去掉冗余)。

可以通过如下链接访问该项目,并下载到最新的liberary文件 tapestry-delegate.dev.java.net。

主要类图如下: 

0 0
原创粉丝点击