Software Development Inheritance and Composition Computer Science 209 Software Development Inheritance and Composition
java.util.stack Class <<Interface>> Iterable <<Interface>> Collection Stack inherits List operations as well as Collection operations Gets Vector to manage its data and provide some of its methods, but at a price! Abstract Collection <<Interface>> List = extends AbstractList = implements Vector Stack
The Price of java.util.Stack Not only can we push, pop, and peek, but we can also get, set, remove, or insert at any position This implementation does not really live up to the spirit of a stack, as would be specified in a much more restricted interface Inheritance is a convenience, but it can be abused
Two Types of Class Relations Inheritance: Class A inherits the attributes and operations of class B, and then adds some of its own; clients can run B’s methods as well as A’s methods Composition: Class A contains an instance variable of class B; clients run only A’s methods, not B’s methods (directly) B A = extends = composes A B
Use Composition = extends = implements = composes <<Interface>> Iterable = extends <<Interface>> Collection = implements Abstract Collection <<Interface>> List = composes ArrayStack AbstractList ArrayStack inherits Collection operations but uses List operations in its implementation Vector ArrayList Stack
Implement with Inheritance public class Stack<E> extends Vector<E>{ public E pop(){ return this.remove(this.size() – 1); } public void push(E newElement){ this.add(newElement); public E peek(){ return this.get(this.size() – 1); // The rest, including a constructor, // are inherited Vector Stack E is a formal type parameter, which is replaced by an actual type when Stack is instantiated
Implement with Composition public class ArrayStack<E> extends AbstractCollection<E>{ private List<E> list; public ArrayStack(){ list = new ArrayList<E>(); } public E pop(E newElement){ list.remove(list.size() - 1); public void push(E newElement){ list.add(newElement); public E peek(){ return list.get(list.size() – 1); Use list instead of this AbstractCollection ArrayStack ArrayList
Implement with Composition public class ArrayStack<E> extends AbstractCollection<E>{ private List<E> list; public ArrayStack(){ list = new ArrayList<E>(); } public int size(){ return list.size(); public boolean add(E newElement){ this.push(newElement) return true; public Iterator<E> iterator(){ return list.iterator(); Last three methods are required by AbstractCollection AbstractCollection ArrayStack ArrayList
Another Implementation of Stacks <<Interface>> Iterable <<Interface>> Collection Abstract Collection LinkedStack ArrayStack LinkedList ArrayList
Add a Single Stack Interface Iterable <<Interface>> Collection = extends <<Interface>> TrueStack Abstract Collection = implements LinkedStack ArrayStack LinkedList ArrayList
Using the Stacks TrueStack<String> s1 = new ArrayStack<String>(); TrueStack<Integer> s2 = new LinkedStack<Integer>(); Supply actual types as arguments for the type parameters
Using the Stacks Wrapping of ints to Integers is automatic TrueStack<String> s1 = new ArrayStack<String>(); TrueStack<Integer> s2 = new LinkedStack<Integer>(); for (int i = 1; i <= 10,; i++) s2.push(i); Wrapping of ints to Integers is automatic
Using the Stacks The for loop comes from the Iterable interface TrueStack<String> s1 = new ArrayStack<String>(); TrueStack<Integer> s2 = new LinkedStack<Integer>(); for (int i = 1; i <= 10,; i++) s2.push(i); for (int i : s2) s1.push(i + ""); The for loop comes from the Iterable interface In what order are a stack’s items visited by the iterator????
Using the Stacks The method addAll comes from AbstractCollection TrueStack<String> s1 = new ArrayStack<String>(); TrueStack<Integer> s2 = new LinkedStack<Integer>(); for (int i = 1; i <= 10; i++) s2.push(i); for (int i : s2) s1.push(i + ""); TrueStack<String> s3 = new LinkedStack<String>(); s3.addAll(s1); The method addAll comes from AbstractCollection
Defining a Stack Interface public interface TrueStack<E> extends Collection<E>{ public E pop(); public void push(E newElement); public E peek(); } <<Interface>> Iterable <<Interface>> Collection <<Interface>> TrueStack
Implementing a Stack Interface public class ArrayStack<E> extends AbstractCollection<E> implements TrueStack<E>{ // As before } <<Interface>> Iterable <<Interface>> Collection <<Interface>> TrueStack Abstract Collection ArrayStack
Interface Polymorphism When two classes implement the same interface, the implemented methods are polymorphic, and we have interface polymorphism <<Interface>> Iterable <<Interface>> Collection <<Interface>> TrueStack LinkedStack ArrayStack
Structural Polymorphism When two classes inherit implementations of the same methods, the implemented methods are polymorphic, and we have structural polymorphism <<Interface>> Iterable <<Interface>> Collection <<Interface>> TrueStack Abstract Collection LinkedStack ArrayStack
For Friday Abstract Classes