Inheritance violates encapsulation unless the superclass’s authors have designed it specifically for the purpose of being extended
The superclass’s implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched. As a consequence, a subclass must evolve in tandem with its superclass, unless the superclass’s authors have designed and documented it specifically for the purpose of being extended.
How to use composition and forwarding technique
Let’s say you want to extend the functionality of the Set interface.
- Create a Forwarding class
- Step 1. Composition
Give your class a private field that references an instance of the existing class (Set)
//your forwarding class
public class ForwardingSet<E> implements Set<E> {
private final Set<E> s;
...
}
- Step 2. Forwarding
Each instance method in the new class invokes the corresponding method on the contained instance of the existing class and returns the results
...
@Override
public boolean add(E e) {
return s.add(e);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return s.addAll(c);
}
...
- Extend the forwarding class
public class InstrumentedSet<E> extends ForwardingSet<E> {
// The number of attempted element insertions
private int addCount = 0;
// constructor
public InstrumentedSet(Set<E> s) {
super(s);
}
@Override
public boolean add(E e) {
...your new implementation ...
}
....other overriden methods...
//your new method
public int getAddCount() {
return addCount;
}
- And it is ready to use
InstrumentedSet<String> s2 = new InstrumentedSet<>(new TreeSet<>());
s2.addAll(Arrays.asList("Snap", "Crackle", "Snap"));
System.out.println("Total: " + s2.getAddCount());