Item 16.pptx
- Количество слайдов: 9
Item 16: Favor composition over inheritance
Inheriting from ordinary concrete classes across package boundaries is dangerous. Inheritance violates encapsulation!
// Broken - Inappropriate use of inheritance! public class Instrumented. Hash. Set < E > extends Hash. Set < E > { // The number of attempted element insertions private int add. Count = 0 ; public Instrumented. Hash. Set ( ) { } public Instrumented. Hash. Set ( int init. Cap, float load. Factor ) { super ( init. Cap, load. Factor ) ; } @Override public boolean add ( E e ) { add. Count ++; return super. add ( e ) ; } @Override public boolean add. All ( Collection extends E > c ) { add. Count += c. size ( ) ; return super. add. All ( c ) ; } public int get. Add. Count ( ) { return add. Count ; } }
Instrumented. Hash. Set < String > s = new Instrumented. Hash. Set < String > ( ) ; s. add. All ( Arrays. as. List ( "Snap" , "Crackle" , "Pop" ) ) ;
get. Add. Count() returns 6, not 3!!!
Bad fixes: • Eliminate overriding of add. All() method. (There is no guaranty of keeping this implementation in further versions of Java) • Totally override add. All() method. (Difficult, time-consuming, and error-prone; not always possible, as some methods cannot be implemented without access to private fields inaccessible to the subclass)
Other problems: • In new version superclass has got a new method that adds elements – elements added via this method aren’t count; • In new version superclass has got a method with the same signature but different return type – it causes compilation error. • In new version superclass has got a method with the same signature – it causes overriding, it is doubtful that your method will fulfill the contract of the new superclass method.
// Wrapper class - uses composition in place of inheritance public class Instrumented. Set < E > extends Forwarding. Set < E > { private int add. Count = 0 ; public Instrumented. Set ( Set < E > s ) { super ( s ) ; } @Override public boolean add ( E e ) { add. Count ++; return super. add ( e ) ; } @Override public boolean add. All ( Collection extends E > c ) { add. Count += c. size ( ) ; return super. add. All ( c ) ; } public int get. Add. Count ( ) { return add. Count ; } }
// Reusable forwarding class public class Forwarding. Set