How can I make this work with java generics

Suppose I have interfaces and concrete like this:

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> {}

      

And I have a global instance:

ReportBuilder<MeterValue> reportBuilder;

      

I would like to change the reportBuilder instance like this:

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

reportBuilder.desiredMethod();

      

By doing this, I get the "Missmatch Type". How can I get the functionality I want? Or how can I improve my class to be more flexible?

Edit:

Wildcard? solved a problem. But other problems also appeared. Let's say I have these methods in my interface:

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"; }
}

      

Let's say I have this instance:

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

      

and

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

      

The getStuff (...) call will not work because the list contains wildcards. One fix would be to change the method of the ReportBuilder interface to:

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

      

But then I break down the specific ReportBuilders. (the list is also a global instance where the content can change)

Any ideas?

+3


source to share


2 answers


I think you should declare the report builder variable as:

ReportBuilder<? extends MeterValue> reportBuilder;

      



This allows you to reportBuilder

have any class reportBuilder

with a common type MeterValue

or any class that implements an interface.

By the way, if you're not already familiar with it, instantiation reportBuilder

seems to resemble a factory pattern , it might be worth reading it. (and of course other templates too.)

+3


source


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

      

Where: ReportBuilder<? extends MeterValue>

means the shared parameter can extend the MeterValue interface.

See the tutorial to learn more about the lookup declaration.




Note. Please review this code in your specific case to avoid the Parallel inheritance smell . If you add a new MeterValue you have to add a ReportBuilder, that should mean you have this problem.




EDIT:

You cannot pass an array with subtypes of MeterValue to ReportBuilderA that asks for at least MeterValueA. This is not a safe type technique. Creating a class after inheritance is more suitable for C ++. In Java, it's best not to change the constraint type after inheritance.

Possible solution, possibly applicable to your specific case:

1) Use one interface for MeterValue. All differences pass to ReportBuilder inheritance. This means you have parallel inheritance in your project.

2) Use the method List<MeterValueA>

when calling getStuff()

. All common logic to process List<MeterValueA>

and List<MeterValueB>

goes to methods with signature:public void sharedLogic(List<? extends MeterValue> list)

+3


source







All Articles