函数Operand
函数Operand的格式如下:函数名(参数1,参数2…)。函数名与Java语法中标示符的命名规范一致,该命名规范已在变量Operand中进行了描述。其每一个参数都是一个Operand,Operand可以是常量、变量、函数或者表达式中的任意一种。如:sum(a)、_formatTime(‘yyyy-mm-dd’,getCurrentTime())、random(23+15)等。
函数Operand的示例代码如下:
EntityMap entityMap = new EntityMapImpl(); entityMap.putEntity("num", 123); try { Operand function = MoqlUtils.createOperand("max(num)"); System.out.println(function.toString() + " " + function.getOperandType()); System.out.println(function.operate(entityMap)); entityMap.putEntity("num", 345); System.out.println(function.operate(entityMap)); //重置函数状态 function.reset(); entityMap.putEntity("num", 12); System.out.println(function.operate(entityMap)); function = MoqlUtils.createOperand("test(1, num, 'a')"); System.out.println(function.toString() + " " + function.getOperandType()); } catch (MoqlException e) { e.printStackTrace(); } |
其执行结果输出如下:
max(num) FUNCTION 123 345 12 test(1,num,'a') FUNCTION |
MOQL目前已支持了部分的函数Operand,如聚集函数Operand:count、sum、avg、min、以及max等。这些Operand在生成后调用operate方法就可以直接对数据进行计算。但如果要创建一个MOQL未支持的函数,MOQL会为其创建一个缺省的Operand,该Operand只是对函数字符串进行了解析,如上面的代码片段中的函数“test(1, num, 'a')”。该函数字符串被解析为一个缺省的函数Operand,但是当我们调用它的operate方法时,它会抛出一个java.lang.UnsupportedOperationException,表示该Operand不支持该方法。为了能够让MOQL也支持test函数,我们需要为test做一个对应的Operand的实现。相关的实现代码如下:
publicclass TestRegistFunction { publicstaticclass Test extends AbstractFunction { public Test(List<Operand> parameters) { /* “test”是该对象对应的函数Operand的名字,3是test函数可以接受的参数数量。若parameters的size与该值不一样时,会抛出IllegalArgumentException,表示输入的函数字符串不合法*/ super("test",3,parameters); functionType = FunctionType.COMMON; } @Override protected Object innerOperate(EntityMap entityMap) { Object obj1 = parameters.get(0).operate(entityMap); Object obj2 = parameters.get(1).operate(entityMap); Object obj3 = parameters.get(2).operate(entityMap); StringBuffer sbuf = new StringBuffer(); sbuf.append(obj1.toString()); sbuf.append("||"); sbuf.append(obj2.toString()); sbuf.append("||"); sbuf.append(obj3.toString()); return sbuf.toString(); } } publicstaticvoid main(String[] args) { EntityMap entityMap = new EntityMapImpl(); entityMap.putEntity("num", 123); try { Operand function = MoqlUtils.createOperand("test(1, num, 'a')"); System.out.println(function.toString() + " " + function.getOperandType()); System.out.println(function.operate(entityMap)); } catch(Exception e) { e.printStackTrace(); } try { //注册test函数的实现 MoqlUtils.registFunction("test", Test.class.getName()); Operand function = MoqlUtils.createOperand("test(1, num, 'a')"); System.out.println(function.toString() + " " + function.getOperandType()); System.out.println(function.operate(entityMap)); } catch (MoqlException e) { e.printStackTrace(); } } }
|
其执行结果输出如下:
test(1,num,'a') FUNCTION java.lang.UnsupportedOperationException at org.moql.operand.function.MemberFunction.innerOperate(MemberFunction.java:49) at org.moql.operand.function.AbstractFunction.operate(AbstractFunction.java:120) at org.moql.core.test.TestRegistFunction.main(TestRegistFunction.java:44) test(1,num,'a') FUNCTION 1||123||a
|
Test类继承了AbstractFunction抽象类,它是test函数的Operand实现。test函数可以接收3个参数,当参数的个数与3不一致时,其构造函数将抛出异常,表示test函数的调用格式不正确,如:test(1,num)将会抛出异常。当我们定义一个函数其参数为变长时,我们可以将3替换为-1,表示变长。或者我们用org.moql.operand.function.Function中的VARIANT_PARAMETERS常量来表示,该值为-1。Test类的主体逻辑在innerOperate中实现,Test类覆写了该方法,将三个参数简单的连接成一个字符串并返回。
从上例代码的执行情况我们看到,在第一次创建test函数的Operand后,调用operate方法抛出了异常;于是在第二次创建test函数的Operand前,我们调用了MOQL的函数注册方法,为test函数注册了Operand的实现类Test。而后我们创建了test函数的Operand并调用了它的operate方法。此次调用获得了预期的输出效果。其根本原因是,第一次创建的函数Operand,因未找到注册的Operand实现,生成了一个缺省的函数Operand,该Operand不支持operate方法;而第二次我们创建函数Operand时,发现了注册的实现类Test,于是绑定了该实现,生成了test函数对应的Operand。
项目地址:http://sourceforge.net/projects/moql/
代码路径:svn://svn.code.sf.net/p/moql/code/trunk