Search code examples
javaextendreturn-type

Abstract class extensions return type


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.


Solution

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