views:

436

answers:

6

A question about composition and object orientation:

I am trying to implement more features for a class (Java TreeMap as an example).

public class TreeMap<K,V> 
   extends AbstractMap<K,V>
   implements NavigableMap<K,V>, Cloneable, Serializable

Using composition is the way to go on this, so I would have to create first a reusable forwarding class, which will wrap the functionality of the class, while at the same time make it do only that so that It can be used elsewhere in the future.

public class ForwardingNavigableMap<K,V> implements NavigableMap<K,V>
{
 ...
}

I would then proceed with creating a wrapper class which inherits the newly created reusable forwarding class, like so:

public class BetterTreeMap<K,V> extends ForwardingNavigableMap<K,V>
{
 /* some new cool features here */
}

What happens If TreeMap contains a number of fine features that I need in my class, that might not be as part of the NavigableMap interface? Should I then proceed in declaring my own interface for TreeMap, and implement that in my reusable class? Any input here is appreciated.

+1  A: 

The simplest approach is to just extend the existing class

public class MyTreeMap<K,V> extends TreeMap<K,V> {
   // add your overridden or extra methods here.
}

I suggest you don't make things more complicated than they need to be.

If this is not suitable, perhaps you could explain what you are trying to achieve.

Peter Lawrey
I am trying to create an object bounding hierarchy for collision detection in a simple game. I am unsure if TreeMap is what I want, so I need to be able to replace it later, which is why the preference of composition over inheritance(extends)
Andreas
Composition allows dynamic changing of the type of the underlying Map. Inhertitance requires a recompilation to change it. How hard will it be to re-compile your code should you want to do this?
Peter Lawrey
+1  A: 

If those cool new features would be implemented on other data structures you will be using, absolutely.

If not, try to avoid overloading you classes with useless interfaces. Keep the clutter to minimum.

Yuval A
+1  A: 

The trouble here is that in this example TreeMap is acting like an interface. You can treat it as such by overriding all its methods to forwarding. It's not like there is much state in an empty TreeMap. However, that is a fragile approach as new methods (or ones you've missed) wont be handled.

Perhaps your class does not need to be a Map. You could create an interface appropriate for your code, but an asMap/asSortedMap/asNavigableMap for use with libraries and non-specific code.

Tom Hawtin - tackline
+1  A: 

What happens If TreeMap contains a number of fine features that I need in my class, that might not be as part of the NavigableMap interface?

This is the problem with using composition in cases like this. If you find yourself making a bunch of wrapper methods that do nothing but call the same methods on TreeMap, that's an argument in favor of inheritance. So if you have a significant number of methods that look like

public Set<K> keySet()
{
    return myTreeMap.keySet();
}

you may just want to extend TreeSet to get all of its methods for free, then override the ones you want to change.

If the class you're designing uses a TreeMap internally, and client programs don't need to know about that, then you should be using composition. If your class is a TreeMap with a few added or changed features, then use inheritance.

Bill the Lizard
+2  A: 

Assuming that you do not intend to make this a pulic API (meaning that you are not shipping it to 3rd parties and expecting them to make use of it) you can do the following.

Given that you (might) require access to TreeMap specific methods, but also might decide later to change the inheritance to be something other than TreeMap, as long as you do not write any code that depends on the class being a TreeMap (eg, never refer to TreeMap aside from the "extends TreeMap") then you are safe using extends. This would require that you write an interface that provided the TreeMap methods.

If you find that you do not want to sue TreeMap and want to use something else later then, since you are not refering to TreeMap anywhere that will be fine. You are then left with all of the calls to TreeMap specific methods... if all of those go away at the same time that you no longer extend from TreeMap then you are good to go. If they do not then you will need to write your own to implementation of the methods that you need.

To find out what you need or not if you changed from TreeMap you would comment out all of the methods you put into the interface you made, if the code compiles with the empty interface you are good to go, if not you need to add the missing methods back into the interface. If the class you decided to extend doesn't provide the missing methods you have work to do (or you did have to extend from TreeMap).

The alternative solution is to figure out in advance if you are really going to need TreeMap. I am not sure that I would want to go too far into a project where I was unsure of what I was needing for my data structures.

TofuBeer
+1  A: 

Put all your own new methods in a new interface, and create a class which implements this interface too.

Here it would be

public class MyMap implements MyInterface, NavigableMap { ... }

You could then let this class extend the class you want, but I would consider it better to have a private member of MyMap being of class TreeMap as you then only expose those methods you actually want and not all those that TreeMap has additionally.

It requires a lot of work to write the forwarding methods, but e.g. Eclipse has good refactorings that allow you to generate them automatically.

Thorbjørn Ravn Andersen