Alex K
Alex K

Reputation: 90

How to use Java generics to avoid overwriting inherited methods (template-like behaviour)?

I want to make a Graph consiting of Nodes in Java. The graph class will be used by different people and different algorithms, so we will need different Node classes for each case, let's say DefaultNode and SpecialNode extends DefaultNode.

Now I want DefaultNode to contain all the general stuff that a Node needs to work, like for example a list of direct neighbours. So I implement this list in DefaultNode:

List<DefaultNode> neighbours = new ArrayList<DefaultNode>();

My problem is now, that I obviously also need this list in the SpecialNode class, but there it should contain and return SpecialNodes. Of course I could overwrite the list and addNeighbour() as well as getNeighbours() methods in every class that inherits from DefaultNode, but that seems redundant and not how OOP is meant to work. I think this would be a perfect case to use templates (like in C++), but afaik there is no such construct in Java, leaving us with Generics.

The solution I came up with so far is the following:

interface INode {}

class DefaultNode<T extends INode> implements INode {

    List<T> neighbours;

    List<T> getNeighbours(){}

    void addNeighbour(T node){}

}

here, the <T extends INode> brackets describe the possible neighbours of this node. So for a SpecialNode I would do:

class SpecialNode extends DefaultNode<SpecialNode> {}

now, while this seems to work as intended, it kind of feels strange... I was surprised that I could not find an easier solution, as this situation seems relatively common. How would you solve this? Is there a better/simpler approach that I missed? Or is the above a viable approach?

Upvotes: 2

Views: 166

Answers (2)

Walter Laan
Walter Laan

Reputation: 2976

If you want to force that the neighbours of a node are of the same type, you can use:

class DefaultNode<T extends DefaultNode<T>> implements INode

though I would make the interface generic (and just call it Node not INode).

Upvotes: -1

NPE
NPE

Reputation: 500663

There is nothing wrong with your approach. In fact, some standard interfaces, such as Comparable are defined in exactly this way:

public class Fruit implements Comparable<Fruit> {
             ^^^^^                       ^^^^^

Upvotes: 2

Related Questions