扩展泛型类并第二次实现其接口

时间:2012-06-02 13:56:07

标签: java spring design-patterns generics cxf

我想提出一个很好的方案:

  • 有一个通用界面,
  • 有各种通用基类实现它,
  • 提供通用基类的子类
  • 以某种方式获得子类的非泛型接口。

困惑?请继续阅读并告诉我您对该解决方案的看法。

假设我希望服务能够根据任何类型的密钥提供任何类型的对象 从任何地方(数据库,文件等)。

为了一个良好的开端,让我们创建一个合适的界面:

public interface ObjectProvider<K, V> {

    V provide(K key);
}

通过这种方式,我将能够提供任何类型的实现。 我想提供数据库和文件中的对象。

假设基于K提供V可以用相同的方法完成 DB逻辑,不管对象类型如何。所以我可以写一个通用的基类 用于数据库访问:

public class DBObjectProvider<K, V> implements ObjectProvider<K, V> {

    public V provide(K key) {
        V v = null;
        //some common DB logic to get V based on K
        return v;
    }
}

实际上,从文件中获取对象也是对象类型独立的:

public class FileObjectProvider<K, V> implements ObjectProvider<K, V> {

    public V provide(K key) {
        V v = null;
        //some common file reading logic to get V based on K
        return v;
    }
}

好的,到目前为止,我有两个通用类可以用来获得我想要的东西。

现在,我想使用其中一个通用实现来获取基于数据库中的String键的String对象。另外,我希望它使用Spring XML定义为bean。 我想没有办法在Spring XML中定义一个通用bean(我是对的吗?)所以我 将创建一个合适的类。我需要做的就是:

public class DBStringStringProvider extends DBObjectProvider<String, String>  {
}

现在我可以将这个bean注入任何:

private ObjectProvider<String, String> objectProvider;

一切都很好,现在是关键部分。 我可以在很多方面使用我有用的DB String-String提供程序(嗯......好吧不是真的)。假设我想制作一个Web服务。 假设我想将DBStringStringProvider公开为CXF Web服务并对其进行测试。 问题是这样的Web服务的客户端代码如下所示:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(<INTERFACE>.class);
<INTERFACE> client = (<INTERFACE>) factory.create();

所以我需要一个DBStringStringProvider的非泛型接口,我没有它,因为它扩展了它的通用基类。

我可以做以下事情:

扩展ObjectProvider&lt; String,String&gt;与另一个接口:

@WebService
public interface StringStringProvider extends ObjectProvider<String, String> {

    @WebMethod
    String provide(String key);
}

另外,在通用基类已经实现的地方实现它:

public class DBStringStringProvider extends DBObjectProvider<String, String>
implements StringStringProvider {
}

我觉得实现基类已经引入的相同接口有点不合适。 但通过这种方式,我可以使用WS客户端:

factory.setServiceClass(StringStringProvider.class);
StringStringProvider client = (StringStringProvider) factory.create();

我的问题是:做我刚刚做的事情是一种好习惯吗?如果没有,还有其他办法吗?

这只是一种情况,在这种情况下,为某些东西设置非通用接口会很棒 已被定义为通用。

1 个答案:

答案 0 :(得分:1)

我不愿批评所提问题中抽象程度的动机。为了界面的一致性和减少重复代码,这些场景不时出现。特别是Java和icky服务框架使这项任务变得比它需要的复杂得多;这种不必要的复杂性并不意味着原始设计是坏的。每天Java都让我因为无意义的冗长而引起我的注意。

我很高兴地确认,定义一个无偿的具体子接口是可以接受和通用的做法。您被迫采取此操作,因为您正在解决服务框架中的限制(不允许参数化接口)。

唯一需要关注的是你真的想在Java中使用 typedef 。我能做的最好的事情w.r.t. Java中的typedef会导致令人难以置信的丑陋构造,这会使得原始帖子中的评论者从他们对复杂性的厌恶判断出来,想要自己测量自己的眼睛。

我怀疑在实践中你会遇到任何问题,但总的来说psuedo-typedefs这样的例子会导致意外的痛苦。在一般情况下,当您创建接口T的简单子接口S时,很有可能使用T代替S,无论它适用于何处。 S可能是一个冗长的参数化Java类表达式,例如,读取或输入的内容很麻烦,T可能很好而且简短。但是对于方法/服务调用/构造函数参数,您仍然需要S作为声明的类型,否则您可能会限制方法或类的有用性。一个人为的例子:

public interface Info extends Map< String, List< FooBar > > {}

public interface Service {
    public Info doSomething( Info info );
}

Service没有理由只接受Info,因为Info不向Map< String, List< FooBar > >添加API;如上所述,doSomething的调用者不能将任何旧地图作为输入;他们必须以某种方式创建一个新的Info并使用该地图的内容对其进行初始化,因为Java(几乎所有其他广泛使用的企业语言)都使用主格输入。