论坛首页 Java企业应用论坛

模板是否应该支持函数调用?

浏览 4731 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-11-21  
首先,将Java中的Method分成:Subroutine和Function两种,
按照“契约式设计原则”的说法,Subroutine是有副作用的(side-effect),而Function是没有副作用,
语法上,Subroutine通常没有返回值,即void方法,而Function则有返回值,
比较明确的是,模板肯定不允许调用Subroutine,否则肯定会引入大量业务逻辑,

现在待讨论的是,模板中是否允许调用Function?
如:
${object.funtion(arg1, arg2)}
衍生出的还有静态Function:
${funtion(arg1, arg2)}

在CommonTemplate(http://www.commontemplate.org)设计之初,
是禁止调用Function的,因为Function会使模板复杂化,通常可以用其它更好的方式表达:
1.无参的Function,可以直接去掉括号,简化成属性方式,如:
String.trim
String.toUpperCase
List.size
Number.toString
等等
2.有参的Function,也可用其它更形象化的操作符处理,如:
用Map[key]代替Map.get(key)
用List[2..4]代替List.subList(2, 4),
将String看作char[]数组,用String[2..4]代替String.substring(2, 4),用String[2]代替String.charAt(2),
用"aa" ~= "AA"(约等于) 代替 "aa".equalsIgnoreCase("AA")
等等

通常处理的Domian对象,都是POJO,基本数据类型,集合类等,
如果标准包对这些都支持的比较好,那禁掉Function看起来是可行的。

然而,标准包不可能想到用户所有的需求,
所以必需留给用户容易实现的扩展点,

以最近版本加入的orderby为例,
假设其不在标准包,而是用户自己扩展实现的,
需求定义:
实现集合类的按属性排序,如:
$for{book : books}
其中,books是一个包含Book的集合,Book是一个POJO,有title, price等属性
现需要在循环之前对books按价格排序,当然可能是升序或者降序,也可能是多个属性,

有三种方案可以实现:
1.扩展静态方法:
$for{book : orderby(books, "price")}
JSP2.0的EL和Velocity就是用的类似此方案
2.扩展对象方法:
$for{book : books.orderby("price")}
3.扩展二元操作符:
$for{book : books orderby "price"}

如果禁止方法调用,当然也应禁止静态方法,
那就只能用第三种,操作符扩展,
但如果这种需求很多,会不会使操作符的数量骤增,
表达式的可读性及易用性都会降低,

看起来,第二种方案比较合理,通过在外部给集合类扩展一个方法,
但就因为这,开启Function调用,是否应该?
   发表时间:2007-11-21  
我感觉只要有个方法调用的许可策略就可以了。 调用方法前,现判断一下,这个方法能不能允许调用,比如,集合类的只读方法,允许访问。 一些静态的工具方法,如字符处理,允许访问。 直接调用方法,模板语法更加简单。当能,map.key这类大家已经普片接受的规则除外。
0 请登录后投票
   发表时间:2007-11-22  
不应该
各有各的职责
职责明确,单一才是最重要的
0 请登录后投票
   发表时间:2007-11-22  
符合javaBean规范的function调用要支持。

比如:

$set a=BussinessService1.***()
$if{a=='1'}
...
$else
...
$end

这样写模版是evil的。这样把模型层的业务代入了视图,MVC中的M无法重用。而

$if(formBean.tag=='1')
...
$else
...
$end

这样是合理的,更优于完全屏蔽function调用

这样的控制比在模型层把tag计算出来,set到Context中更有效,更具有封装性,否则模型层的计算就成了一堆散列的参数计算,非常零乱。

也就说,建议,对符合javaBean规范的function调用支持,比如formBean.tag,就必须有getTag,和setTag才允许调用。


0 请登录后投票
   发表时间:2007-11-23  
leadyu 写道

符合javaBean规范的function调用要支持。
...
也就说,建议,对符合javaBean规范的function调用支持,比如formBean.tag,就必须有getTag,和setTag才允许调用


这个肯定是支持的,bean.getProperty()和bean.isProperty()都可以用bean.property调用,

非符合Bean规范的部分也支持(因为JDK中不是所有取值函都支持Bean规范),如:String.trim,List.size等

jindw 写道

我感觉只要有个方法调用的许可策略就可以了

这个想法不错,规则可定义比较好,
如,可定义许可:
Object.get*, Object.is*, String.trim, List.Size
而像remove等禁止。
(注:List的remove方法违反契约式设计原则,它不是无副作用的函数,但却有返回值)




现在,模板引擎把bean.function(arg1, arg2)的语法解析已经实现了,
只是在配置中,加了一项:
functionAailable=false

默认禁止,如果实在需要,可自行开启。

算是中庸的解决办法。
0 请登录后投票
   发表时间:2007-11-23  

不是Object.get*都行,必须有对应的set*,才允许调,单纯的get*,很多都是业务性质的函数,比如查询方法。^_^
0 请登录后投票
   发表时间:2007-11-23  
要是不允许函数调用怎么处理递归数据呢?
0 请登录后投票
   发表时间:2007-11-24  
递归可以考虑用lambda表达式的不动点算子实现

lambda表达式:
http://javatar.iteye.com/blog/137037
0 请登录后投票
   发表时间:2007-11-24  
leadyu 写道

不是Object.get*都行,必须有对应的set*,才允许调,单纯的get*,很多都是业务性质的函数,比如查询方法。^_^


那如果是只读属性呢?
0 请登录后投票
   发表时间:2007-11-25  
其实,我觉得jindow的想法蛮好,你可以把策略这层抽象出来,
类似JDK里面reflect里面的PrivilegeControl,在所有方法调用前拦截。

我只是提出这个策略干脆就以javaBean规范为准算了,毕竟广为接受,同时能够很好的规避业务方法。

当然,bean.size,map.key,这些可以例外,至于你说的问题,你想想有没更好的策略了。只是单纯get*个人认为是不合适的。

至于只读属性,我只能说 i m sorry ,why dont you follow JavaBeans Specification?why? 活该!

而且视图层又没参与持久化,哪来只读可写之分,呵呵。当然你可以想想这个策略。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics