1

I've got two class: GraphNode and BTNode extends GraphNode. I've got method:

public GraphNode.addChild(GraphNode node)

as GraphNode may have many children and two methods:

public BTNode.addLeftChild(BTNode left)
public BTNode.addRightChild(BTNode right)

as BTNode may have only two children

How may I restrict public access to inherited addChild(GraphNode node) method from BTNode class? I wouldn't like to have that publicly accessible from that level (while remaining public access from GraphNode class)?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Malvinka
  • 1,185
  • 1
  • 15
  • 36
  • 1
    You can't do that, but what you *can* do is implement `addChild` and have it throw an exception with a good error message that explains why this method shouldn't be used here and what *should* be used instead. Now, all that said, maybe you should re-consider inheritance, because it feels that `BTNode` doesn't have that much in common with `GraphNode` after all... – Nir Alfasi Aug 26 '17 at 15:16
  • 1
    You probably may have to ask yourself, is the right way to inherit from the parent class? You are trying to violate the Liskov substitution principle over there. I guess you should rethink your design. – Ervin Szilagyi Aug 26 '17 at 15:17
  • I was thinking about design and it indeed looks like problem here. HOWEVER I cannot see why is so as the only difference between BTNode and GraphNode is that that first may have only two children. Binary Tree IS indeed a special version of graph isn't it? – Malvinka Aug 26 '17 at 15:25
  • I don't like the idea of letting the user use the method only to throw an exception. BUT maybe the solution would be to let him add only two children (assuming that left and right is not important for the user so assigning them just in order) and THEN throwing an exception when the user tries to add more children? – Malvinka Aug 26 '17 at 15:27
  • 2
    Likewise a square is a special version of a rectangle but you don't inherit a square from a rectangle, otherwise you violate Liskov's principle: https://stackoverflow.com/questions/1030521/is-deriving-square-from-rectangle-a-violation-of-liskovs-substitution-principle – Ervin Szilagyi Aug 26 '17 at 15:33
  • I am still not sure if I understand the concept correctly... do you think that's the case? Could you possibly explain me that on "binary tree node <-> graph node" example? – Malvinka Aug 26 '17 at 15:39
  • I decided to ask that as a new question, I hope that's ok.https://stackoverflow.com/questions/45897182/is-deriving-binarytreenode-from-graphnode-a-violation-of-liskovs-substitution-p – Malvinka Aug 26 '17 at 15:51

3 Answers3

4

If you extend (or implement) from a class (or interface) then the parent will specify the whole signature of a method. There is nothing you can change about it, you will always need to have the method public if your parent specifies it as public.

Otherwise you would run into problems when casting like ((Parent) child).theMethod(). The object itself is child but the view gets reduced to the Parent class. The method gets invoked from the child class, so it would be private although you casted it to Parent which specified it as public.

However you could do something like:

public class Child extends Parent {
    @Override
    public void theMethod() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    private void otherMethod {
        // Do something
    }
}

But note that saying "I am extending class XY but not supporting all of its methods" is not the best design. It is a sign that the parent class (or other parts of the architecture) could have been structured more modular in the first place.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • Thank you for great answer. It is clear now why such operation is impossible. And, tbh, I've neven seen that class of exception before ;) However I don't like the idea of letting the user to call a method only to throw an exception, I have an idea how to use it properly now. – Malvinka Aug 26 '17 at 15:29
  • You're welcome. Most of such problems come from an improper architecture/structure and can be avoided simply by using a better suited one. You are right that saying "*I am extending class XY but not supporting all of its methods*" is not the best design. It is a sign that the parent class could have been structured more modular in the first place. Good to here that you have found a better one :) – Zabuzard Aug 26 '17 at 15:31
1

It is not possible to reduce the visibility of a method in subclass. The subclass need to be a valid instance of the base class.

ishimwe
  • 1,216
  • 12
  • 13
0

As you can see in the previous answers, it is not possible to change visibility of public methods in the child classes. But in case of you are designer of GraphNode class, you could use a little bit another class hierarchy:

public abstract class BaseNode {
    protected final Map<String, GraphNode> children = new HashMap<>();

    protected void addChild(String id, GraphNode node) {
        children.put(id, node);
    }
}

public class GraphNode extends BaseNode {
    public void addChild(GraphNode node) {
        children.put(String.valueOf(System.currentTimeMillis()), node);
    }
}

public class BTNode extends BaseNode {
    private static final String LEFT = "left";
    private static final String RIGHT = "right";

    public void addLeftChild(BTNode node) {
        addChild(LEFT, node);
    }

    public void addRightChild(BTNode node) {
        addChild(RIGHT, node);
    }
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35