Frage

I have an abstract class that is extended by two other classes. In the abstract class I have a method that is implemented differently by those two classes. I want to be able to use that method even if I don't know which concrete class object it is. Is there a way to make the return type the same as what the method was used on not the abstract type?

To make it more concrete, the relevant part of abstract class:

public abstract class State<abstarct> {


public abstract Set<State<?>> findNeighbors();

And for the other two classes:

public class PuzzleState extends State<PuzzleState> {

    @Override
public Set<PuzzleState> findNeighbors() {
    // making the set
    // unrelevant to the question
    return set;
}

and

public class QueensState extends State<QueensState> {

@Override
public Set<QueensState> findNeighbors() {
    // making the set
    // unrelevant to the question
    return set;
}

For now it doesn't work of course. I just thought State might be what I was looking for but it isn't. Is there a way to make it work? I want the findNeighbors() to return either Set or Set according to what the method was used on. I want it to be that way because in another part of the program I have a display() method that takes as an input either PuzzleState or QueensState and displays it accordingly.

I don't know if my question was clear enough, but basically I just want to know if there is a way to change the abstract methods return type according to the class.

War es hilfreich?

Lösung

Why is State declared as generic ? I dont see any specific value by doing that. If all you want to achieve is to be able to return concrete States from subclases , you can as well do this way :

abstract class State {
   public abstract Set<? extends State> findNeighbors();
}

and then your sub states as :

class PuzzleState extends State {
@Override
public Set<PuzzleState> findNeighbors() {
    Set<PuzzleState> set = new HashSet<PuzzleState>();
    return set;
}
}

and

class QueensState extends State {
@Override
public Set<QueensState> findNeighbors() {
    Set<QueensState> set = new HashSet<QueensState>();
    return set;
}
 }

EDIT after OPs first comment :

I have classes for displaying which need to know whether it is a state of Puzzle or the state of Queen

If your processing logic depends upon the knowledge of concrete types and cannot work polymorphically based on the abstract type - then thats most likely a design issue/smell if you want to stick to SOLID design principles.

You can think of refactoring the parts of your code that display the particular state like this :

In each concrete State ( ie PuzzleState and QueenState here ) have the logic of returning an interface StateImage and then in the part of gui where you want to render your states' visual form - use interface ImageRenderer

abstract class State implements StateDisplayable{ public abstract Set<? extends State> findNeighbors(); }

class PuzzleState extends State {
@Override
public Set<PuzzleState> findNeighbors() {
    Set<PuzzleState> set = new HashSet<PuzzleState>();
    return set;
}

public Image getImage(){
    return new PuzzleStateImage();  // implement this for Puzzle !!
}

  }



class QueensState extends State {
@Override
public Set<QueensState> findNeighbors() {
    Set<QueensState> set = new HashSet<QueensState>();
    return set;
}

public Image getImage(){
    return new QueenStateImage();  // implement this for QueenState!!
}

}


abstract class Image {
     abstract void draw();
 }

class PuzzleStateImage extends Image {
void draw() {
    // knows what/how to render PuzzleState for a visual component
}
}



class QueenStateImage extends Image {
  void draw() {
    // knows what/how to render QueenStateImage for a visual component
  }
}



interface StateDisplayable {
    Image getImage();
}

interface StateRenderer {
    void draw(Image state);
}

and then in GUI code

void display(){
    StateRenderer renderer = null ; // instantiate 
    Set<? extends State> states = null; // get your states here ( this is a mix of Puzzle and Queen states - but you dont care about the concrete type )
    for(StateDisplayable state : states){
        Image stateImage = state.getImage();  // this could be Puzzle or Queen stateImage
        renderer.draw(stateImage);
    }
}

Andere Tipps

You can use the same pattern used by Enum:

public abstract class State<T extends State<T>> {
  public abstract Set<T> findNeighbors();
}

This will work as you require for the first level subclasses of State but if you had a second level, e.g.

public class SudokuState extends PuzzleState

Then the findNeighbors of SudokuState would still have to return a Set<PuzzleState>.

Java allows for covariant return type overrides, i.e. a subclass can override a superclass method and change the return type to a subtype of the parent's return type (you can override a method returning Object with one that returns String, for instance), but generics aren't covariant - Set<String> is not a subtype of Set<Object>.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top