Groovy探索 DSL在Calendar類上的實踐 一

hivon發表於2009-03-19

                  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

 

  }

 

}

相關文章