Groovy探索之Delegate模式 三

        Groovy探索之Delegate模式 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

 

在前面的两篇中,我们共提到了在Groovy语言中两种动态委派的方法。其实,前面的两种动态委派的方法,归根到底都是使用了“invokeMethod”方法。

Groovy语言中,我们还有一种不使用到“invokeMethod”方法的委派方法,这就是我们在这一篇中要讲到的内容;除此之外,我们还要把我们的委派模式以一个实践中要使用到的例子来作为我们整个系列文字的结尾。

我们都知道,在Groovy语言中,方法是可以作为对象来使用的,只不过这时候的方法在Groovy语言中被成为闭包,前面我们已经花了很大的篇幅来谈到闭包,关于闭包的知识,大家可以参阅系列文字《Groovy探索之闭包》。既然方法可以作为对象来使用,那么它也就可以被用来赋值了。这就是我们的第三种委派的方法的核心思想。

我们还是以整个系列文字中用到的Foo类的例子来讲解。

 

class Foo {

   

    def test()

    {

       println 'have a test'

    }

   

    def foo()

    {

       println 'foo...'

    }

 

}

 

 

我们有一个Foo5的类,如下:

 

class Foo5

{

    def testAgain()

    {

       println 'test it again'

    }

}

 

 

现在我们的Foo5类希望拥有Foo类的两个方法。我们的想法是,在运行时取得Foo5类的metaClass,然后再把Foo类的方法赋给Foo5类。整个想法都很简单,感觉应该是可行的,下面我们就来试一试。

     

      def foo = new Foo()

     

      Foo5.metaClass."test" = foo.&"test"

     

      Foo5.metaClass."foo" = foo.&"foo"

     

      def f = new Foo5()

     

      f.test()

      f.foo()

      f.testAgain()

   

 

 

首先是初始化一个Foo类的对象,目的是为了获取它的两个方法对象。然后,使用“foo.&"test"”和“foo.&"foo"”取得Foo类的两个方法;最后,通过Foo5类的metaClassFoo5类创建两个方法,并把Foo类的两个方法的实现赋值给它们。

再下面就是它们的测试代码,结果如下:

have a test

foo...

test it again

 

 

上面我们就说完了委派技术的第三种方法,委派技术到此也可以告一段落。需要重述一遍的是,委派技术很重要,它是我们很多其他技术的基础,如代理模式、拦截器技术、组合模式等等。所以,我们需要花大力气掌握它。

 

我们在使用Struts等框架开发应用程序的时候,Action类是我们最需要打交道的类。需要为每一个动作或每一个模块编写一个Action类,在这其中,所以的Action类,或者说大部分的Action类都要做一些相同的动作,比如扑捉一些共同的Exception、记录log等等一些其他的事情。这时候,我们的解决方案是使用模板方法模式,为Action类写一个BaseAction类,把这些公共的事情在BaseAction类里做完。

代码形如下面的样子:

 

    public final String load()

    {

       try

       {

           //do somethings that all actions need to do

           ……

 

           //do somethings that action itself

           return doLoad();

       }

       catch(CannotGetJdbcConnectionException e)

       {

           return "errorPage";

       }

    }

    protected String doLoad()

    {

       return SUCCESS;

}

 

 

在“load”方法里把公共的事情做完,其他的事情让子类在“doLoad”方法里实现。这是一个很优雅的解决方案。

但是有两个明显的缺陷:第一,在父类里已经将子类的方法名定义了,在Java编程中,我们的方法名是要告诉我们方法要做的事情的,比如,“load”说明这个方法对应的页面是load详细数据的。而在父类里已经定义了方法名,使得子类不得不使用,会导致方法名不能和它所做事情对应。第二,父类只能定义有限个方法,这使得有些模块所要用到的方法只比父类定义的方法多那么一两个,却不得不再写一个类来定义它们,使用起来特别的不方便。

基于上面的分析,使用模板方法来解决这个问题并不是一个十分完美的解决方案。而我们使用动态委派技术却能十分完美的解决上面的问题。

import org.codehaus.groovy.runtime.InvokerHelper

 

class BaseAction extends groovy.lang.DelegatingMetaClass{

   

    BaseAction(final Class aclass)

    {

        super(aclass);

        initialize()

    }

   

    public Object invokeMethod(Object a_object, String a_methodName, Object[] a_arguments)

    {

       try

       {

           //do somethings that all actions need to do

           ……

 

           //do somethings that action itself

 

           super.invokeMethod(a_object, a_methodName, a_arguments)

 

       }

       catch(CannotGetJdbcConnectionException e)

       {

           return "errorPage";

       }

      

    }

}

 

 

可以看到,动态委派技术完满的完成了我们的BaseAction的业务要求,在技术上,BaseAction又没有强制定义子类Action的方法名,各个Action类可以自己定义各自的方法名;而且BaseAction类对方法个数也没有限制,原则上来说各个Action类可以定义任意多的方法。

展开阅读全文

没有更多推荐了,返回首页