java - 扩展泛型类并第二次实现其接口(interface)

标签 java spring design-patterns generics cxf

我想展示一个场景,最好:

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

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

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

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

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 注入(inject)到任何:

private ObjectProvider<String, String> objectProvider;

一切都很好,现在是关键部分。 我可以通过多种方式利用有用的 DB String-String 提供程序(嗯……好吧,不是真的)。假设我想用它来做一个网络服务。 假设我想将 DBStringStringProvider 公开为 CXF Web 服务并对其进行测试。 问题是此类 Web 服务的客户端代码如下所示:

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

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

我可以执行以下操作:

用另一个接口(interface)扩展 ObjectProvider 接口(interface):

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

    @WebMethod
    String provide(String key);
}

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

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

对于实现基类已经引入的相同接口(interface),我感到有点不舒服。 但这样我就可以使用 WS 客户端了:

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

我的问题是:我刚才所做的事情是一个好的做法吗?如果不行还有其他办法吗?

这只是一种场景,如果有一个非通用接口(interface)就好了 这已被定义为通用。

最佳答案

我不愿意批评所提出问题的抽象程度的动机。为了接口(interface)的一致性和减少重复代码,这些场景时有发生。 Java,尤其是令人讨厌的服务框架,使这项任务比实际需要的复杂得多;这种不必要的复杂性并不意味着最初的设计很糟糕。每天,Java 都让我因各种与毫无意义的冗长相关的原因而咬紧牙关。

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

唯一需要关心的是您确实在尝试在 Java 中执行typedef。我能做的最好的事。 Java 中的 typedef 会导致极其丑陋的结构,这会让您原始帖子的评论者(从他们对复杂性的厌恶来看)想要衡量自己的眼睛。

我怀疑在实践中你会遇到任何问题,但总的来说psuedo-typedefs像这个例子可能会引起意想不到的痛苦。在一般情况下,当您创建一个简单的子接口(interface) T 时接口(interface)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 的调用者不能将任何旧 map 作为输入;他们必须创建一个新的 Info以某种方式使用该映射的内容对其进行初始化,因为 Java(与几乎所有其他广泛使用的企业语言一样)使用主格类型。

关于java - 扩展泛型类并第二次实现其接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10862859/

相关文章:

java - 为什么 Collections.copy 仍然复制引用,它不克隆复制的对象?

java - CDI 中的 session 范围是如何实现的?

spring - AWS Elastic Beanstalk - 配置我的 nginx 设置以增加 Java Spring maven 应用程序的超时

java - 数据映射器模式 : where to put a checkLogin method for a User Model?

objective-c - 递归类设计模式 : Options and Best Practices

java - 当我想拦截一个方法时,我只能用接口(interface)子类化吗?

java - php以JSON形式回显多维数组

java - 获取今天日期的所有优惠

java - 如何在 Spring HandlerInterceptorAdapter 中将 header 添加到 http 响应?

c# - 使用参数更正工厂方法的实现