Groovy探索 DSL在Calendar类上的实践 一
作为一个使用者,我不喜欢Java平台的Calendar类;同样,我也不喜欢Groovy平台的Calendar类。都是基于同样的原因,使用起来非常不方便。
同时,Groovy语言的DSL极大的吸引了我。使得我每每在使用Calendar类的时候,都会想到我可否使用DSL来改造这个Calendar类呢,权当一次使用DSL的实验。
在这样的想法下,我写了一点的DSL代码,用来检验我对于DSL的理解,同时,也想抛砖引玉,引来大家对于使用DSL来改造Calendar类的一些想法。
首先,我不喜欢使用如下的代码来获取单独的年、月、日的数据:
Calendar c = Calendar.getInstance();
System.out.println(c.get(Calendar.YEAR));
我喜欢形如"c.year"这样的代码来获取单独的年、月、日的数据。这种想法很简单,实现起来也不难,不就是给Calendar类多加几个"get"方法嘛。
我构造起我自己的Calendar类来,如下所示:
class MyCalendar {
def cal
def type
def MyCalendar()
{
cal = Calendar.instance
}
def getDate()
{
cal.get(Calendar.DATE)
}
def getMonth()
{
cal.get(Calendar.MONTH)+1
}
def getYear()
{
cal.get(Calendar.YEAR)
}
}
一切都很简单,现在,我们来测试一下吧:
def c = new MyCalendar()
println c.year+'/'+c.month+'/'+c.date
运行结果为:
2009/3/16
真的还蛮顺利的。
接着,我也不喜欢Calendar类的"set"方法,它的形式是这样的:
c.set(Calendar.YEAR, 2010);
如果我既想设定年份,还想设定月份,那么必须这么写:
c.set(Calendar.YEAR, 2010);
c.set(Calendar.MONTH, 3);
我喜欢这样的形式:
c.set(year:2010)
这也很简单啊,不就是一个Map参数的方法嘛,于是,我在MyCalendar类里继续加入了如下的方法:
def set(map)
{
if(map.year)
{
cal.set(Calendar.YEAR,map.year)
}
if(map.month)
{
cal.set(Calendar.MONTH,map.month)
}
if(map.date)
{
cal.set(Calendar.DATE,map.date)
}
}
现在,我们就可以写代码来测试一下了:
def c = new MyCalendar()
c.set(year:2010)
println c.year+'/'+c.month+'/'+c.date
运行的结果为:
2010/3/16
当然了,如果我们既想设定年份,又想设定月份,代码就是形如下面的形式:
c.set(year:2010,month:4)
对于年份的运算,比如当前年份加上3年,我就更不喜欢下面的形式了:
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, c.get(Calendar.YEAR)+3);
System.out.println(c.get(Calendar.YEAR));
我喜欢下面的形式:
c = c+3.year
要达到上述的目的,我们首先要在MyCalendar类里重载"plus"方法,使得MyCalendar类能够和数字相加。
def plus(howlong)
{
if(type==1)
{
cal.set(Calendar.YEAR,getYear()+howlong)
}
else if(type==2)
{
cal.set(Calendar.MONTH,getMonth()+howlong)
}
else if(type==3)
{
cal.set(Calendar.DATE,getDate()+howlong)
}
this
}
首先判定相加的数字是年份、月份还是日期,然后再使用Calendar类的加法。
接着,光重载"plus"方法还不够,我们需要识别形如"3.year"这样的表达式。在这里,Groovy语言的MOP能帮得上忙。
def mc = new ExpandoMetaClass(Integer.class,true)
mc.getDate <<
{
->
c.type = 3
delegate
}
mc.getMonth <<
{
->
c.type = 2
delegate
}
mc.getYear <<
{
->
c.type = 3
delegate
}
mc.initialize()
当所有这一切完成之后,我们就可以来测试了:
c = c+3.date
println c.year+'/'+c.month+'/'+c.date
c = c+2.month
println c.year+'/'+c.month+'/'+c.date
运行结果为:
2010/5/19
2010/8/19
最后,我把整个的Calendar类的代码附上。
class MyCalendar {
def cal
def type
def MyCalendar()
{
cal = Calendar.instance
}
def getDate()
{
cal.get(Calendar.DATE)
}
def getMonth()
{
cal.get(Calendar.MONTH)+1
}
def getYear()
{
cal.get(Calendar.YEAR)
}
def plus(howlong)
{
if(type==1)
{
cal.set(Calendar.YEAR,getYear()+howlong)
}
else if(type==2)
{
cal.set(Calendar.MONTH,getMonth()+howlong)
}
else if(type==3)
{
cal.set(Calendar.DATE,getDate()+howlong)
}
this
}
def set(map)
{
if(map.year)
{
cal.set(Calendar.YEAR,map.year)
}
if(map.month)
{
cal.set(Calendar.MONTH,map.month)
}
if(map.date)
{
cal.set(Calendar.DATE,map.date)
}
}
static void main(args) {
def c = new MyCalendar()
println c.year+'/'+c.month+'/'+c.date
c.set(year:2010,month:4)
println c.year+'/'+c.month+'/'+c.date
def mc = new ExpandoMetaClass(Integer.class,true)
mc.getDate <<
{
->
c.type = 3
delegate
}
mc.getMonth <<
{
->
c.type = 2
delegate
}
mc.getYear <<
{
->
c.type = 3
delegate
}
mc.initialize()
c = c+3.date
println c.year+'/'+c.month+'/'+c.date
c = c+2.month
println c.year+'/'+c.month+'/'+c.date
}
}