views:

153

answers:

5

Hi,

So I'm working on creating a visualization for a data structure in Java. I already have the implementation of the data structure (Binary Search Tree) to start with, but I need to add some additional functionality to the included node class. As far as conventions and best practices are concerned, should I create a subclass of the node with this added functionality or should I just modify what I have and document it there?

My question is similar to what's asked here but that's a little over my head.

I know it probably doesn't matter much for what I'm doing, so I'm asking this more as a general thing.

Edit: I probably should have been more clear. My modifications don't actually change the original implementation other than to add a couple of extra fields (x and y coords plus a boolean to set whether that node is highlighted) and functions to access/modify those fields. Also the node class I'm working with is included in the BST implementation

From reading your answers it seems like there's arguments to be made for either case. I agree that creating a separate class or interface is probably the best thing to do in general. Creating another class seems like it could get tricky since you'd still need a way to extract the data out of the node. The BST implementation I'm using is generic and doesn't have any such functionality by itself in the Node class or the BST class to just return the data so at minimum I have to add that.

Thanks for the informative replies.

+2  A: 

I would say that in the general case of adding functionality to an existing implementation, you should extend the existing implementation rather than modify it.

And here's my reasoning. If that node is used anywhere aside from the Binary Search Tree implementation, then when you modify it you'll need to find everywhere it is used to ensure that none of those places conflict with your modifications. While just adding functionality in the form of new methods generally won't cause problems, it could cause problems. You never know how an object is used.

Second, even if it is only used in the Binary Search Tree, you'll still need to make sure that the BST's implementation will play nice with your modifications.

Finally, if you do extend it, you don't have to worry about points one and two. And you get the added bonus of having your modifications kept separate from the original implementation for all time. This will make it easier to track what you have done and comment on it.

Daniel Bingham
I'm not sure if extending will work in all cases. If, say, a tree base class wants to create a new object in an area protected from 'overriding' so you can't return your own object using your class instead, you're essentially buggered.
Chris Dennett
@Chris Very true. That's when its time to get creative ;)
Daniel Bingham
+11  A: 

The question to answer is, is the 'base functionality' useful, even disirable, when you're not visualizing the data structure?

You might not even want to extend the class at all. Without more detail, it seems to me that you have a datastructure that works. You could create a NEW class that knows how to vizualise it.

That is, instead of a datastructure than knows how to visualize itself, you have a datastructure, and another class that knows how to visualize the datastructure. Heck - you may find that that evolves into another whole class hierarchy because you might need to visualize queues, stacks, etc. etc. NOTHING to do wiht your binary search tree.

n8wrl
++ Perfect. Each class should do exactly one thing well. Storing data and visualizing data are 2 things.
Bill K
+3  A: 

Since you're asking in general, here's the short answer: it really depends on the situation.

First off, subclasses are assumed to have an "IS-A" relationship with their parent classes. If you can't say that your new subclass IS A specific kind of the original class, you're asking the wrong question, and should be making a new, unrelated class.

  • If the new code is closely related to the core purpose of the class, and applies to all members of the class (e.g. all BSTs), it may be better to modify. High cohesion is good.
  • If your new code is related to the core purpose of the class but has to do with only some objects of that type (e.g. only BSTs that are balanced), subclassing is probably the way to go.
  • Depending on what you're changing, how many places your code is used, how many different people/organizations are using it, &c., your changes might lead to unexpected behavior in other code, so you should think twice before modifying existing code. That doesn't mean automatically subclassing commonly used things; that would often be wrong for the reasons described above.

In your specific case, I agree with n8wrl; since visualization has nothing to do with data structures, it's probably better to implement a whole separate Visualizable interface than make a DrawableBSTNode subclass.

Lord Torgamus
A: 

Mixing up logically independent functionalities will cause a mess. Subclassing is a very special relationship, often overused. Subclassing is for Is-a-Kind relationships.

If you want to visualize something, why not create a fully independent Class for that? You could simply pass your Node object to this. (Or even better, use an Interface.)

sibidiba
+2  A: 

There's no simple answer, knowing when and how to add functionality is a something you have to learn over time.

Just adding to the base class seems like the easy solution, but it's polluting your base class. If this is a class you could reasonably expect another program (or even part of your program) to use does the functionality you are adding make sense in the context of your class's responsibility? If it doesn't this is probably a bad move. Are you adding dependencies linking your base class to your specific use? Because if you are that's throwing code reuse right out the window.

Inheriting is the solution a lot of engineers gravitate to, and it's a seductive route. But as I've grown as an engineer it's one that I use sparingly. Inheritance should only be used in true is-a relationships, and you need to respect behavioral subtyping or you are going to regret it later on. And since Java only allows single inheritance it means you only get one shot at subtyping.

Composition (especially with interfaces) is often a better idea. Often what looks like a is-a relationship is really a has-a one. Or sometimes all you really need is a helper class, that has many functions that take your original class as an argument.

However with composition there is one issue, want to store these objects in your tree. The solution here is interfaces. You don't want a tree that stores Nodes. You want to objects that have an interface that can give you a node.

public interface HasNode {
    public Node getNode();
}

Your node class is a HasNode with getNode just returning this. Your NodeVisualizer class is also a HasNode, and now you can store NodeVisualizers in your tree as well. Of course now you have another problem, your tree could contain NodeVisualizers and Nodes, and that wouldn't be good. Plus when you get a HasNode back from the tree functions you have to cast them to the right instance and that's ugly. You'll want to use templates for that, but that's another answer.

aspo