如何为方法创建代理?

时间:2014-11-21 14:35:03

标签: java design-patterns

问题

我有一个包含多种方法的服务类,如下所示。本课程结尾处描述了这门课程的具体内容。

public class Service{
    public Foo m_a( /* args_a */ ){ ... }
    public Bar m_b( /* args_b */ ){ ... }
    // and so on
}

该服务中的所有公共方法都有一个共同点:它们在执行任何其他操作之前调用init()方法。所以,我的服务看起来像这样:

public class Service{
    private int attr;
    private void init(int val){ 
        this.attr = val; 
    } 

    public Foo m_a(int val_a, ...){
        init(val_a); 
        // time for business A
    }
    public Bar m_b(int val_b, ...){
        init(val_b);
        // time for business B
    }
    // and so on
}

由于将来可能会向Service添加其他方法,我认为上面的设计很差。为此类实现新方法的人可能不会遵循先调用init(val_x)的规则,这可能会导致错误。

解决方案草案

为了确保始终调用init(),我可以创建一些系统地完成工作的代理方法:

public class Service{

    // Init method
    private int attr;
    private void init(int val){ 
        this.attr = val; 
    }

    /* 
     * The only public method in the service is a proxy, 
     * that always calls init() before calling the actual requested method
     */
    public Object invoke(String method, int val, Map<String,Object> args){  

        init(val);

        switch(method){
            case "m_a":
                return m_a(args.get("name"),...);
            case "m_b":
                return m_b(args.get("myArg"),...);
            default: // launch some exception
        }
    }

    private Foo m_a( /* args_a */ ){ ... }
    private Bar m_b( /* args_b */ ){ ... }
    // and so on
}

我认为这是一个更好的方法,而且必须维护代码的开发人员可以毫不费力地理解正在发生的事情。

但是我发现这个解决方案有一个很大的缺点:用户的可用性!

  • 在调用Map方法之前,必须将所有参数放在invoke对象中,而不是直接在方法签名中输入参数
  • 返回的invoke类型为Object,非常含糊不清,要求用户在每次调用invoke
  • 时应用投射

你们对如何解决这些问题有任何明智的想法,并且仍然保留这种代理理念吗?

Service

的工作

我实际上在做的是实现REST API。此API的目标是访问存储在数据库中的特定资源。例如:

GET http://fortheking.com/topic/3

此HTTP请求将链接到一个服务方法,该方法根据其ID获取特定主题。

在实践中,&#34;主题&#34;是要访问的资源的名称。它是我的Service类的每个方法的入口点,因此在实际启动方法的预期逻辑之前,需要应用一些公共代码。我已将此类代码放入init()

1 个答案:

答案 0 :(得分:1)

从根本上说,您希望将Java Proxy与ImplementationHandler一起使用。这个博客有点过时,但解释了基本概念:http://www.ibm.com/developerworks/library/j-jtp08305/ - &#34;动态代理作为装饰者&#34;部分可能与您最相关。我们的想法是,您将返回一个服务&#34;实例到您的调用者,它实际上是一个代理对象。在该代理InvocationHandler中,您可以调用init()方法然后执行main方法。如果你有现有的方法也调用init(),你需要确保init()是幂等的,或者更改代码不要调用它两次。

此方法的一个限制是您只能为接口创建代理,而不能为类创建代理。 (除非在我最近看过的Java版本中已经解除了这个限制。)我认识到上面的示例代码是简化的,但是你没有显示任何接口,所以这可能是你需要的东西先介绍一下。最重要的是,您的服务的调用者必须直接使用Interface而不是Service类。