3

假设我有这个接口和具体:

public interface MeterValue {}
public class MeterValueA implements MeterValue {}
public class MeterValueB implements MeterValue {}

public interface ReportBuilder<T extends MeterValue> {} 
public class ReportBuilderA implements ReportBuilder<MeterValueA> {}
public class ReportBuilderB implements ReportBuilder<MeterValueB> {}

我有一个全局实例:

ReportBuilder<MeterValue> reportBuilder;

我想改变 reportBuilder 实例如下:

if (isA())
   reportBuilder = new ReportBuilderA();
else
   reportBuilder = new ReportBuilderB();

reportBuilder.desiredMethod();

这样做我得到“类型不匹配”。如何获得我想要的功能?或者我怎样才能改进我的课堂设计,使其更加灵活?

编辑:

通配符?解决了这个问题。但也引入了其他问题。假设我在界面中有这个方法:

public interface ReportBuilder<T extends MeterValue> {
     public String getStuff(List<T> values);
} 

public class ReportBuilderA implements ReportBuilder<MeterValueA> {
     @Override
     public String getStuff(List<MeterValueA> values) { return "A"; }
}

public class ReportBuilderB implements ReportBuilder<MeterValueB> {
     @Override
     public String getStuff(List<MeterValueB> values) { return "B"; }
}

假设我有这个实例:

  ReportBuilder<? extends MeterValue> reportBuilder = new ReportBuilderA();

和:

  List<? extends MeterValue> list = new ArrayList<MeterValueA>();
  String s = reportBuilder.getStuff(list);

由于列表包含通配符,因此对 getStuff(...) 的调用将不起作用。一种解决方法是将 ReportBuilder 接口方法修改为:

public String getStuff(List<? extends MeterValue> values);

但后来我打破了具体的 ReportBuilders。(列表也是一个全局实例,内容可能会有所不同)

有任何想法吗?

4

2 回答 2

3

我认为您应该将报告生成器变量声明为:

ReportBuilder<? extends MeterValue> reportBuilder;

这允许reportBuilder有任何ReportBuilder类,具有泛型类型MeterValue,或任何实现接口的类。

顺便说一句,如果您还不熟悉它,创建ReportBuilder实例似乎类似于工厂方法模式,可能值得一读。(当然还有其他模式。)

于 2013-02-01T09:14:21.537 回答
3
public interface MeterValue {}

public class MeterValueA implements MeterValue {}

public class MeterValueB implements MeterValue {}

public interface ReportBuilder<T extends MeterValue> {
    void desiredMethod();
}

public class ReportBuilderA implements ReportBuilder<MeterValueA> {
    @Override
    public void desiredMethod() {}
}

public class ReportBuilderB implements ReportBuilder<MeterValueB> {
    @Override
    public void desiredMethod() {}
}

void f() {
    ReportBuilder<? extends MeterValue> reportBuilder = null;

    if (Math.random() > 0.5)
        reportBuilder = new ReportBuilderA();
    else
        reportBuilder = new ReportBuilderB();

    reportBuilder.desiredMethod();
}

其中:ReportBuilder<? extends MeterValue>表示泛型参数可以扩展MeterValue接口。

请参阅教程以阅读有关通配符声明的更多说明。


注意:请在您的特定情况下查看此代码以避免并行继承气味。如果要添加一些新的 MeterValue 你应该添加 ReportBuilder 这应该意味着你可能有这个问题。


编辑:

您不能将具有 MeterValue 子类型的数组传递给至少需要 MeterValueA 的 ReportBuilderA。它不是类型安全技术。继承后实例化具体类更适合 C++。在 Java 中,最好不要在继承后更改受限类型。

可能的解决方案,可能适用于您的具体案例:

1) MeterValue 使用单一接口。所有差异都转移到 ReportBuilder 继承。这意味着您在项目中具有并行继承。

2)List<MeterValueA>调用getStuff()方法时使用具体。所有用于处理的共享逻辑List<MeterValueA>List<MeterValueB>移至带有签名的方法:public void sharedLogic(List<? extends MeterValue> list)

于 2013-02-01T09:15:33.130 回答