繁体   English   中英

将通用服务与其实现和子类型绑定

[英]Binding generic service with its implementation and subtypes

免责声明:请耐心等待我提供大量代码来解释该场景。

在其中一个 maven 模块(核心)中,我们有以下类:

abstract class ReportingEvent {
}

abstract class Element {

    public <E extends ReportingEvent> Optional<E> getReportEvent() {
        return Optional.empty();
    }

}

服务,例如:

public interface Reporting<E extends ReportingEvent> {
    void report(E event);
}

interface InternalService {
}

public class InternalServiceImpl implements InternalService {

    @Inject
    Reporting<ReportingEvent> reporting; // 1. Possible to use a generic type? How?

    private void reportEvents(BatchRequest batchRequest) {
        batchRequest.stream()
                // section below is of importance
                .map(m -> m.getEntity().getReportEvent()) // the generic method from 'Element'
                .filter(Optional::isPresent)
                .map(Optional::get)
                .forEach(event -> reporting.report(event)); // method from 'Reporting'
    }
}

class CoreBindingModule extends AbstractModule {
    protected void configure() {
        bind(InternalService.class).to(InternalServiceImpl.class).in(Singleton.class);
    }
}

此外,在我们部署的另一个 maven 模块(消费者)中,我们有与上述相关并实现上述内容的类:

abstract class BaseReporting extends ReportingEvent {
}

class ColdReporting extends BaseReporting {
}

abstract class Node extends Element {
}

class Cold extends Node {
    @Override
    public Optional<ColdReporting> getReportEvent() {
        return Optional.ofNullable(new ColdReporting()); // some business logic
    }
}

class ReportingImpl implements Reporting<ReportingEvent> { // 2. Use 'BaseReporting' here
    void report(ReportingEvent event){}
}

class ConsumerBindingModule extends AbstractModule {
    protected void configure() {
        bind(new TypeLiteral<Reporting<ReportingEvent>>() {}).to(ReportingImpl.class).in(Singleton.class);
    }
}

上面的代码工作正常。 但问题是使用了与模块不太相关的类型。

A...所以如果我将消费者模块中的绑定更改为

bind(new TypeLiteral<Reporting<BaseReporting>>() {}).to(ReportingImpl.class).in(Singleton.class);

class ReportingImpl implements Reporting<BaseReporting> {
    void report(BaseReporting event){}
}

我收到一个错误

No implementation for Reporting<ReportEvent> was bound. while locating Reporting<ReportEvent> for field at InternalServiceImpl.reporting(InternalServiceImpl.java:21)

这是相关的,无论如何我都无法在核心模块中使用Reporting<BaseReporting>

B...另一方面,如果我尝试将Reporting注入为:

@Inject
Reporting<? extends ReportingEvent> reporting;

然后 IDEA 声明

 Required type: capture of ? Provided: ReportingEvent

在线上

...forEach(event -> reporting.report(event))

在尝试解决代码部分中提到的12 时,有没有办法解决这种情况?

(我可能会在很大程度上重申您已经知道的内容)

撇开与 Guice 相关的模块和配置,您的问题可以写成

Reporting<ReportingEvent> reportingEvent = new ReportingImpl();
Reporting<? extends ReportingEvent> reporting = baseReporting;
reporting.report(reportingEvent); //won't work

这与

List<? extends String> list = new ArrayList<>();
list.add("a"); //won't work

说,你有一个扩展BaseReportingHotReporting类,因此你有这样的东西

public class ReportingImpl implements Reporting<ReportingEvent> { 
    public void report(ReportingEvent event){}
}
public class ColdReportingImpl implements Reporting<ColdReporting> { 
    public void report(ColdReporting event){}
}

public class HotReportingImpl implements Reporting<HotReporting> { 
    public void report(HotReporting event){}
}

假设您HotReportingImpl为字段Reporting<? extends ReportingEvent> reporting注入了一个HotReportingImpl Reporting<? extends ReportingEvent> reporting Reporting<? extends ReportingEvent> reporting

在您的代码中,如果m.getEntity().getReportEvent()返回ColdReporting怎样? 它与这里的report方法所期望的不兼容(一个HotReporting )。


选项1:

我会尝试摆脱泛型类型参数并将Reporting定义为

public interface Reporting {
    void report(ReportingEvent event);
}

public class BaseReportingImpl implements Reporting {
    @Override
    public void report(ReportingEvent event) {

    }
}
//... and so on

问题:

  • 如果您在实现中依赖ReportingEvent的确切子类型(需要不好的类型转换)。
  • 尽管如此, HotReportingImpl可以获取ColdReporting对象作为参数。

选项 2:

您可以通过向其添加类型参数来使InternalService泛型


如果实现类Reporting必须处理的具体类型ReportingEvent ,那么它看起来不正确的Element返回基本类型( ReportingEvent )。

看看Joshua Bloch 的 Typesafe 异构容器 你的问题与此重叠。 您可以使用该类型参数维护从ReportingEvent的类型到相应的Reporting子类的映射。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM