我有一个包含多种方法的服务类,如下所示。本课程结尾处描述了这门课程的具体内容。
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()
。
答案 0 :(得分:1)
从根本上说,您希望将Java Proxy与ImplementationHandler一起使用。这个博客有点过时,但解释了基本概念:http://www.ibm.com/developerworks/library/j-jtp08305/ - &#34;动态代理作为装饰者&#34;部分可能与您最相关。我们的想法是,您将返回一个服务&#34;实例到您的调用者,它实际上是一个代理对象。在该代理InvocationHandler中,您可以调用init()方法然后执行main方法。如果你有现有的方法也调用init(),你需要确保init()是幂等的,或者更改代码不要调用它两次。
此方法的一个限制是您只能为接口创建代理,而不能为类创建代理。 (除非在我最近看过的Java版本中已经解除了这个限制。)我认识到上面的示例代码是简化的,但是你没有显示任何接口,所以这可能是你需要的东西先介绍一下。最重要的是,您的服务的调用者必须直接使用Interface而不是Service类。