views:

100

answers:

4

(This is a hypothetical question for discussion, I have no actual problem).

Say that I'm making an implementation of SortedSet by extending LinkedHashMap:

class LinkedHashSortedMapThing extends LinkedHashMap implements SortedSet {
 ...
}

Now programmers who use this class may do

LinkedHashMap x = new LinkedHashSortedMapThing();

But what if I consider the extending of LinkedHashMap an implementation detail, and do not want it to be a part of the class' contract? If people use the line above, I can no longer freely change this detail without worrying about breaking existing code. Is there any way to prevent this sort of thing, other than favouring composition over inheritance (which is not always possible due to private/protected members)?

+7  A: 

If you extend a class, you inherit its public interface and there is no way to avoid this AFAIK. Composition would be the favourable solution indeed, as you are not supposed to depend on the internals of LinkedHashMap anyway - these can also change in future JDK versions.

Java has no private inheritance as C++ do (which is practically more or less equivalent to composition anyway).

Péter Török
+11  A: 

I think the easiest way would be to make a private inner class that extends LinkedHashMap, and have LinkedHashSortedMapThing keep a reference to that and point all its methods there.

class LinkedHashSortedMapthing implements SortedSet {
    private class Foo extends LinkedHashMap {
        ...
    }

    private Foo foo;

    public void clear() {foo.clear();}
    public boolean containsValue(Object value) {return foo.containsValue(value);}
    ...
}
Michael Mrozek
+1 this is a nice solution, I like it :-)
Péter Török
If you want to read further on this topic, Michael Mrozek's solution is to use what's called composition instead of inheritance, as discussed here: http://www.artima.com/designtechniques/compoinh.html.
apollodude217
Oh, he specifically said "other than favouring composition over inheritance (which is not always possible due to private/protected members)?"; I didn't realize that's what this is called. This works even for private methods though, so I'm not sure why that was a concern
Michael Mrozek
Because that doesn't work :P. A private method cannot be used outside the class it's defined in, even in subclasses. If you only need access to protected+ members then it's fine though.
Bart van Heukelom
@Bart Private methods, yes, but you couldn't have accessed those through your example either; `LinkedHashSortedMapThing` can't call them
Michael Mrozek
Aye, that be true
Bart van Heukelom
A: 

You can implement SortedSet by aggregation, so that the public interface of the class does not include LinkedListHashMap

class LinkedHashSortedMapThing extends AbstractSet implemenents SortedSet
{
    LinkedListHashMap map;


    public int size() {
       return map.size();
    }
}
mdma
A: 

First, the code should declare the variable with the interface Set or SortedSet. But you can hide the implementation by Not inheriting from LinkedHashMap. Just implement the interface and delegate to a LinkedHashMap member.

If you need protected access to LinkedHashMap functionality, use a private inner class as the delegation member.

Arne Burmeister