0

I have a class TreeNode, a class LeafNode which extends TreeNode and a class ParentNode that extends TreeNode as well. In the class ParentNode I have a method getChild that returns a TreeNode.

Whenever I call getChild successively, I have to do a bunch of downcasting.

LeafNode myLeafNode = (LeafNode) ((ParentNode) this.getChild(id1)).getChild(id2)

Is there a way I can avoid all this downcasting without changing the inheritance structure of my program?

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
755
  • 2,991
  • 3
  • 20
  • 34
  • 2
    Looks like you have a design problem. Could you explain further about the current design of your tree (or your data structure)? – Luiggi Mendoza Jul 25 '13 at 17:39
  • It's a pretty generic tree structure; a single ParentNode can have several children that are either LeafNodes or ParentNodes. Every node is a TreeNode. – 755 Jul 25 '13 at 17:41
  • And what's the meaningful difference between a `ParentNode` and a `LeafNode`? I mean, what makes a difference between these classes to make you decide to split them instead of using a single one? – Luiggi Mendoza Jul 25 '13 at 17:43
  • Basically, the leaf nodes in my data structure must carry several fields that non-leaf nodes do not, and vice versa. For example, the leaf nodes have values such as "value" and "creationDate" etc. that non-leaf nodes don't, but non-leaf nodes have values such as "children" etc. that leaf nodes don't – 755 Jul 25 '13 at 17:45
  • I think it would be helpful to post a lot more of your code here; at least the relevant bits of the definitions of TreeNode, LeafNode and ParentNode. – Elemental Jul 25 '13 at 17:47
  • Well, you can have a `MyData` class that holds your several fields, and use a `MyData data` field in a `Node` class that represents both `ParentNode` and `LeafNode`. Anyway, when inserting a new `Node`, your `LeafNode` would have to turn into a `ParentNode` thus giving you more code to maintain (this includes the excessive downcasting). – Luiggi Mendoza Jul 25 '13 at 17:48

3 Answers3

1

You should only extend a class if the child has specific logic inappropriate for the parent.

I'm not sure why you need anything but "Node". The "Root" node acts exactly like every other node, and if you assume that the left and right child nodes can be empty, a "Leaf" acts exactly like a node (with two empty child nodes)

Just a piece of advice--it's nice to know about "extends" but be careful of over using it, I made a project much harder than it had to be once by over-using extends. Most classes tend to have a very simple lineage or none at all.

Every time you think to extend an object I suggest you think about the is-a/has-a rule first and then even if it is a "is-a" try to consider containment anyway, if containment isn't much harder just use that. In the long run it will make your life easier.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • In addition to the is-a/has-a rule, one of my college professors told us that if you've got a class hierarchy where an object would reasonably be expected to change its class due to normal, expected changes in its state/properties, then you're probably modeling it wrong. If you're modeling cars, you probably don't want an OrangeCar class and a BlackCar class, where simply getting a paint job causes you to need to convert classes. So if adding a child node to a leaf node causes you to to throw out the LeafNode and create a ParentNode instead for it, then it's probably not the right design. – Tim Jul 26 '13 at 21:54
0

If the method getChild() is in the TreeNode class, then I don't think you need the cast to ParentNode.

dkatzel
  • 31,188
  • 3
  • 63
  • 67
0

If the methods you're trying to call (not only getChild() but also whatever you plan to do with the LeafNode once you find it) are defined in TreeNode, then you won't need to cast back and forth. Even if some operations don't make sense for leaf nodes (or non-leaf nodes, whichever), you can define them with an empty implementation and then rely on your code only to only call the valid ones (assuming your code is able to do that).

Tim
  • 2,027
  • 15
  • 24