1

我想提出一个场景,它会很好:

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

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

假设我想要一个服务来提供基于任何类型的键和来自任何地方(数据库、文件等)的任何类型的对象。

作为一个好的开始,让我们创建一个适当的接口:

public interface ObjectProvider<K, V> {

    V provide(K key);
}

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

让我们假设无论对象类型如何,都可以使用相同的数据库逻辑来提供基于 K 的 V。所以我可以为数据库访问编写一个通用基类:

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 提供程序(hhmmm... 好吧不是真的)。假设我想用它制作一个 Web 服务。假设我想将 DBStringStringProvider 公开为 CXF Web 服务并对其进行测试。问题是此类 Web 服务的客户端代码如下所示:

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

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

我可以执行以下操作:

用另一个接口扩展 ObjectProvider<String, String> 接口:

@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();

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

这只是一种情况,如果为已定义为通用的东西提供非通用接口会很棒。

4

1 回答 1

1

我不愿批评所提出问题的抽象程度的动机。为了接口的一致性和减少重复代码,这些场景时有发生。Java,尤其是 icky 服务框架,使这项任务比它需要的复杂得多;这种不必要的复杂性并不意味着原始设计不好。Java 每天都让我咬紧牙关,原因有很多,都是毫无意义的冗长。

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

唯一需要注意的是,您真的在尝试在 Java中执行typedef 。我已经能够在 Java 中执行 typedef 的最好结果导致了一个令人震惊的丑陋结构,这将使您原始帖子的评论者,从他们对复杂性的厌恶来看,想要衡量他们自己的眼睛。

我怀疑在实践中你会遇到任何问题,但总的来说,像这个例子这样的伪类型定义会导致意想不到的痛苦。在一般情况下,当您创建一个普通的 interface 子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添加任何 API 。Map< String, List< FooBar > >正如所写,doSomething 的调用者不能将任何旧地图作为输入;他们必须以Info某种方式创建一个新的并使用该映射的内容对其进行初始化,因为 Java(与几乎所有其他广泛使用的企业语言一样)使用主格类型。

于 2012-06-23T04:00:05.173 回答