View RSS Feed

Java Object

Composition Rather than Inheritance

Rate this Entry
by , 11-29-2011 at 01:27 AM (1028 Views)
One of the more abused features of object oriented languages is inheritance. Second on the list of abused features of Java as an outgrowth of inheritance is the use of polymorphism. Developers seem to believe that everything should be inherited, and that classes should use polymorphism for every object irrespective of whether the arguments will be provided from external sources. Doing these sorts of things will make your designs more difficult to understand and lead to complications later when you need to make changes later to your system. This is because by using inheritance you have created a hierarchy of objects even when it has no real relevance to the objects that you have chosen to model.

One of the best but maybe least known core design patterns for object oriented systems is the approach of using composition instead of inheritance, especially in cases where it is not clear which approach that you should apply. The benefit of composition is that it does not force a design into an inheritance hierarchy. Composition leaves you with more flexibility as it’s always possible to dynamically choose a type (and thus behavior) using composition, whereas inheritance requires an exact type to be known at compile time. Another reason is that inheritance violates the idea of encapsulation since it depends on the implementation details of its superclass in order to function properly. I will show this in the example below:

How not to use of inheritance!
Java Code:
public class SoundHashSet<E> extends HashSet<E> { 
	// The number of attempted element insertions 
	private int addCount = 0;

	public SoundHashSet() { 
	}

	public SoundHashSet(int initCap, float loadFactor) {
	    super(initCap, loadFactor);
	}

	@Override 
	public boolean add(E e) { 
	    addCount++;
	    return super.add(e);
	} 

	@Override 
	public boolean addAll(Collection<? extends E> c) {
	    addCount += c.size(); 
	    return super.addAll(c);
	} 

	public int getAddCount() {
	    return addCount;
	}
}
In the example above is a program that uses a HashSet. We need to query the HashSet on the number of elements that have been added since it was created. So in order to provide this functionality, I write a HashSet variant that keeps count of the number of attempted element insertions and exports an accessor for this count. The HashSet class now has two methods capable of adding elements, add and addAll, so we override both of these methods. This doesn’t work! Why? Assume that I addd a couple of elements to it.

Java Code:
SoundHashSet<String> s = 
	new SoundHashSet<String>();
s.addAll(Arrays.asList("Hiss", "Bang", "Boom", “Wow”));
Although one would expect the getAddCount method to return four in fact it returns eight! Internally, HashSet’s addAll method is implemented on top of its add method, although HashSet, though this is not documented. The addAll method in SoundHashSet added three to addCount and then invoked HashSet’s addAll implementation using super.addAll. This in turn invoked the add method, as overridden in SoundHashSet, once for each element. Each of these four invocations added one more to addCount, for a total increase of eight: each element added with the addAll method is double-counted.

If you use composition, you could instead give your class a private field that references an instance of an existing class thus each existing class becomes a component of the new one. In this case, the new class invokes the corresponding method on the contained instance of the existing class and returns the result. In the case of SoundHashSet, it would look like the following:

Same class using composition
Java Code:
public class InstrumentedSet<E> extends ForwardingSet<E> { 
	private int addCount = 0;
	public InstrumentedSet(Set<E> s) { super(s);
	}
	@Override 
	public boolean add(E e) { 
	    addCount++;
	    return super.add(e);
	} 

	@Override 
	public boolean addAll(Collection<? extends E> c) {
	    addCount += c.size(); 
	    return super.addAll(c);
	}
 
	public int getAddCount() {
	    return addCount;
	}
}
The forwarding class
Java Code:
public class ForwardingSet<E> implements Set<E> { 
    private final Set<E> s; 
    public ForwardingSet(Set<E> s) {   this.s = s; }
    public void clear() 			{ s.clear();			}
    public boolean contains(Object o) { return s.contains(o);	}
    public boolean isEmpty() 		{ return s.isEmpty();	}
    public int size() 			{ return s.size();		}
    public Iterator<E> iterator() 	{ return s.iterator();	}
    public boolean add(E e) 		{ return s.add(e);		}
    public boolean remove(Object o)	{ return s.remove(o);	}
    public boolean containsAll(Collection<?> c)
						{ return s.containsAll(c); } 	     
    public boolean addAll(Collection<? extends E> c)
						{ return s.addAll(c);	} 
    public boolean removeAll(Collection<?> c)
						{ return s.removeAll(c);	} 
    public boolean retainAll(Collection<?> c)
						{ return s.retainAll(c);	} 
    public Object[] toArray()		{ return s.toArray(); } 
    public <T> T[] toArray(T[] a)	{ return s.toArray(a); }
    @Override public boolean equals(Object o) 
						{ return s.equals(o); }
    @Override public int hashCode()	{ return s.hashCode(); } 
    @Override public String toString() { return s.toString(); }
}

Submit "Composition Rather than Inheritance" to Facebook Submit "Composition Rather than Inheritance" to Digg Submit "Composition Rather than Inheritance" to del.icio.us Submit "Composition Rather than Inheritance" to StumbleUpon Submit "Composition Rather than Inheritance" to Google

Comments