Title: Applying Inheritance to Solve problems
1Applying Inheritance to Solve problems
2Applied Inheritance
- Decide on the classes involved from the problem
description - Group classes into conceptually equivalent groups
- Per group of classes, the generalizing concept
will be a Parent to those classes - Distribute responsibilities amongst all classes
based on what is appropriate - and customary for that class.
Example
A program to teach geometry needs to model some
basic shapes. All shapes have surface area,
could have volume and location. The shapes that
need to be modeled are Circle, Rectangle,
Sphere, Cylinder, and a Square. What classes
will you need? Draw an UML diagram showing class
relationships if any.
3Example
Classes Circle, Rectangle, Sphere, Cylinder,
Square, Coordinate
Group classes
All Shapes
2D Shapes
Circle
Sphere
Coordinate
Rectangle
Cylinder
Square
3D Shapes
Square is a Rectangle
Inheritance hierarchy
4Example
Distribute Responsibilities
Shape getSurfaceArea() clone() equals() toStr
ing() Object getLocation()
Shape3D getVolume()
Shape2D ?
Is Shape2D needed?
5Example Abstract classes.
public abstract class Shape public abstract
double getSurfaceArea() public abstract
Object getLocation() public abstract Object
clone() public abstract String toString()
public abstract boolean equals()
Observe the syntax of Shape. The methods are not
empty methods
Abstract Class
A class with at least one unimplemented method.
Shape above is an example of an Abstract class.
Interface
A class with only unimplemented methods.
public interface Shape public double
getSurfaceArea() public Object
getLocation() public Object clone()
public String toString() public boolean
equals()
6Abstract Classes
- An abstract class is a placeholder
- It is too generic to be of use by itself.
- It is used in a class hierarchy to organize
common features at appropriate levels. - Abstract class cannot be instantiated
- However an abstract class variable can reference
any concrete derived object. - An abstract method has no implementation, just a
signature - It is never intended to be called directly (a
placeholder). - Abstract methods can appear only in classes that
themselves been declared abstract - The modifier abstract is used to define abstract
classes methods - The children of the abstract class are expected
to define implementations for the abstract
methods in ways appropriate for them - ??If a child class does not define all abstract
methods of the parent, then the child is also
abstract!
7Interfaces vs Abstract classes, how to decide?
Not all programming languages have Interfaces!
1 unimplemented method
2 unimplemented method
All methods unimplemented
All methods implemented
Abstract class
Interface
Regular Class
So why have abstract classes and interfaces?
- To enforce design conformity.
- Clients can expect a uniform set of methods for
related classes. - Interfaces are used to tag a class with a
property. While interfaces - are classes, they represent action ideas,
verbs or properties - about class.
8Interfaces...
Sample Interfaces
Cloneable, Drawable, Colorable, Runable,
Comparable,
Q How do you inherit from an interface? A By
implementing the interface.
extends
public interface Shape implements Cloneable
public abstract class Shape2D implements Shape
Q How do you inherit from an Abstract class? A
The usual way, by extending
public class Circle extends Shape2D
9Its all still inheritance!
extends
public interface Shape implements Clonable
public abstract class Shape2D implements
Shape public class Circle extends
Shape2D
Client Code Circle c new Circle() Shape s
c Cloneable cln s Shape2D s2d (Shape2D)s
- Circle has to implement all
- unimplemented methods of
- 2DShape
- Shape
- Clonable
10Its all still inheritance!
Client Code Circle c new Circle() Shape s
c Cloneable cln s Shape2D s2d
(Shape2D) s
through c you can access ALL methods of Circle
AND its parents!
Through s you can access ONLY methods of Shape
and Cloneable implemented in Circle
Through cln you can access ONLY methods of
Cloneable implemented in Circle
Through s2d you can access ONLY methods of Shape,
Cloneable, and Shape2D implemented in Circle.
11Multiple Inheritance
Some programming languages allow for multiple
inheritance.
In Java
Can have multiple interface implementation
. Single inheritance.
Types of possible inheritance
- An interface can inherit from multiple interfaces
by implementing
- A class (abstract or otherwise) can inherit from
multiple interfaces by - implementing
- A class (abstract or otherwise) can inherit from
a single other (abstract or - normal) class.
12A harder Example
A Stack Machine is a device that lets you write
simple programs that use a Stack. Items (in our
example numbers) are placed on and removed from
the stack using two commands push to place on,
and pop to take off. Items are always placed on
top of the stack and taken off the top of the
stack. A stack is a last-in-first-out structure.
Arithmetic operations can be performed by
assuming that the two operands needed for the
operation will be the top two items on the stack
and the answer will be placed back on the stack.
push 5
push 10
add
10
15
5
5
Stack
Stack
Stack
Any mathematical expression can be converted into
a series of machine instructions.
push 5 push 4 subtract push 6 multiply push
5 add print
5 (6 (5 - 4))
13Example
What are the classes?
Clients view
public static void main(String args)
StackMachine sm new StackMachine()
sm.load(programFileName) sm.run()
StackMachine Coordinate all operations. void
load(String fileName) void run()
14Example gaining an understanding
example.stk push 5 push 4 subtract push
6 multiply push 5 add print
public class StackMachine ProgramLoader pl
Stack stack public StackMachine()
pl new ProgramLoader() stack new
Stack() public void load(String
fileName) pl.load(fileName)
public void run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) System.out.printl
n(instruction)
Client code public static void main(String
args) StackMachine sm new StackMachine()
sm.load(example.stk) sm.run()
What happens here?
15Example implementing the instructions - one
solution
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() if (command.toUpperCase
(PUSH) String parameter
st.nextToken() stack.push(Double.parseDouble
(parameter)) else if (command.toUpperCase(PR
INT) double d stack.pop()
System.out.println(d)
Messy, long, yuck,
16Example another way
Think of instruction as classes and group them
instructions
Organized by number of parameters
pop
divide
add
push
subtract
print
multiply
one parameter instruction
no parameter instruction
Organized by function
arithmetic instructions
instructions
multiply
stack instructions
divide
add
push
subtract
pop
print
utility instructions
17Example another way
Instruction
OneParameterInstruction
OneParameterInstruction
push
pop
add
multiply
divide
subtract
print
Instruction
ArithmeticInstruction
UtilityInstruction
StackInstruction
push
pop
add subtract divide multiply
print
- Each instruction will know how to execute
itself - Each instruction will know how to initialize
itself.
18Example another way
public interface Instruction public void
load(StringTokenizer) public void
execute(Stack)
public abstract class ArithmeticInstruction
implements Instruction public void
load(StringTokenizer st)
Quick Review Whats going on? Add a new
Add() Instruction i a i.load(st) i.execute(st
ack)
public class Add extends ArithmeticInstruction
public void execute(Stack stack)
double operand1 stack.pop() double
operand2 stack.pop()
stack.push(operand1operand2)
19Example another way
public interface Instruction public void
load(StringTokenizer) public void
execute(Stack)
public abstract class StackInstruction implements
Instruction //only here for design
completeness
public class Pop extends StackInstruction
public void load(StringTokenizer st) public
void execute(Stack stack) stack.pop()
public class Push extends StackInstruction
double value public void load(StringTokenizer
st) String parameter st.nextToken() value
Double.parseDouble(parameter) public
void execute(Stack stack) stack.push(value)
20Example another way
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() if
(command.toUpperCase().equals(PUSH)) Push
p new Push() p.load(st)
p.execute(stack) else if (command.toUpperCase()
.equals(SUBTRACT)) Subtract p new
Subtract() p.load(st)
p.execute(stack)
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() if
(command.toUpperCase().equals(PUSH)) Push
p new Push() p.load(st)
p.execute(stack) else if (command.toUpperCase()
.equals(SUBTRACT)) Subtract p new
Subtract() p.load(st)
p.execute(stack)
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() if
(command.toUpperCase().equals(PUSH)) Push
p new Push() p.load(st)
p.execute(stack) else if (command.toUpperCase()
.equals(SUBTRACT)) Subtract p new
Subtract() p.load(st)
p.execute(stack)
Will this work?
Is it any better?
common code!
21Example another way
Will this work?
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() if
(command.toUpperCase().equals(PUSH)) Push
p new Push() else if (command.toUpperCase().e
quals(SUBTRACT)) Subtract p new
Subtract() else if p.load(st) p.execu
te(stack) //for
Common code factored out.
Will this work? Why or why not?
22Example another way
Will this work?
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() Instruction p
if (command.toUpperCase().equals(PUSH))
p new Push() //upcast else if
(command.toUpperCase().equals(SUBTRACT))
p new Subtract() //upcast
p.load(st) //method overriding p.execute(stac
k) //method overriding //for
23Example another way
public class StackMachine public void
run() String instruction
for(int i0 iltpl.numInstructions()
i) instruction pl.get(i) StringTokenizer
st new StringTokenizer(instruction) String
command st.nextToken() try Instruction
instRef (Instruction) (Class.forName(command)).n
ewInstance() instRef.load(st)
instRef.execute(stack) catch(Exception e)
System.out.println(Syntax error - bad
instruction) System.exit(0)
A really cool way to do all that!
Client code public static void main(String
args) StackMachine sm new StackMachine()
sm.load(example.stk) sm.run()