Title: Mechanisms for Software Reuse
1Session 35
- Mechanisms for Software Reuse
2Getting Started
- We BEGIN with a fairly fast review of some slides
from last time
3An Exercise
- The physics department would like for us to write
a simple ball world program that it can use to
teach concepts of friction. In this program, we
need for some MovableBalls to decelerate. Every
time one of these decelerating balls moves, its
speed decreases by 5. - Add a DeceleratingBall class to the Ball
hierarchy for this purpose.
4A Possible Solution
- public class DeceleratingBall extends MovableBall
- public DeceleratingBall( int x, int y, int r,
double dx, double dy ) - super( x, y, r, dx, dy )
-
- public void move()
- super.move()
- setMotion( xMotion() 0.95,
- yMotion() 0.95 )
-
-
- We create a DeceleratingBall just as we would a
MovableBall - DeceleratingBall b new DeceleratingBall( 10,
15, 5, 5.0, 10.0 )
5A New Wrinkle
- Running the program, we realize that some
decelerating balls need to bounce off the walls
they hit, too. So we need a class of BoundedBalls
that decelerate. - But that just generates nearly duplicate code!
6The Problem
- The Problem
- We would like to add a behavior to a set of
classes that share a common interface. - The Tempting Solution that Fails
- Use inheritance to create a new class of objects
that has the behavior. - Use instances of this class when you need the
behavior, and use instances of the superclass
otherwise. - This solution is impractical. Why?
- We will need to create multiple subclasses and
replicate the behavior in each. - What if we would like to add more behavior to the
extended object? We have to make (many!) more
subclasses!
7An Alternative Solution
- BoundedBalls respond to the same set of messages
as MovableBalls. So they are substitutable for
one another. Can we use this to our advantage? - public class DeceleratingBall extends MovableBall
- private MovableBall workerBall
- public DeceleratingBall( MovableBall aBall )
- super()
- workerBall aBall
-
- public void move()
- workerBall.move()
- workerBall.setMotion(
- workerBall.xMotion() 0.95,
- workerBall.yMotion() 0.95 )
-
8An Alternative Solution
- // ALL OTHER MESSAGES ARE DELEGATED
- // DIRECTLY TO THE INSTANCE VARIABLE!
- public void paint( Graphics g )
- workerBall.paint( g )
-
- public void setColor( Color newColor )
- workerBall.setColor( newColor )
-
- protected int radius()
- return workerBall.radius()
-
- ...
- // -------------------------------------------
- protected double xMotion()
- return workerBall.xMotion()
-
- ...
9Using DeceleratingBalls
- Now, we create a DeceleratingBall by giving it a
MovableBall to direct - DeceleratingBall b
- new DeceleratingBall(
- new MovableBall(10, 15, 5, 2.0, 5.0 ) )
- What is the advantage of this?
10Using DeceleratingBalls
- Now, we create a DeceleratingBall by giving it a
MovableBall to direct - DeceleratingBall b
- new DeceleratingBall(
- new BoundedBall(10, 15, 5, 2.0, 5.0, this ) )
11(No Transcript)
12How Good is Our New Solution?
- What are the weaknesses of our new approach?
- It is more complex.
- Decelerating balls are a bit bigger and
slower at run time.
13How Good is Our New Solution?
- What are the strengths of our new approach?
- It says it once and only once. The move()
method specific to deceleration behavior occurs
in one class. The deceleration factor lives in
exactly one class. - We can add deceleration behavior to any
MovableBall with this same class! - We can add deceleration behavior to any future
subclass of MovableBallwith no new code!! - The tedious task of writing the delegation
methods can be done automatically within many OO
programming tools. In any case, writing them once
seems more palatable than writing multiple
subclasses for deceleration throughout the
hierarchy.
14The New Ball Hierarchy
15An Exercise
- Add an ExpandingBall class to the MovableBall
hierarchy. An ExpandingBall becomes a little bit
larger every time it moves. Use the delegation
technique we used for the DeceleratingBall class.
16An Exercise
- Add an ExpandingBall class to the MovableBall
hierarchy. An ExpandingBall becomes a little bit
larger every time it moves. Use the delegation
technique we used for the DeceleratingBall class. - public class ExpandingBall extends MovableBall
- private MovableBall workerBall
- public ExpandingBall( MovableBall aBall )
- super()
- workerBall aBall
-
- public void move()
- workerBall.move()
- workerBall.region().height (workerBall.region()
.height 11) / 10 - workerBall.region().width (workerBall.region().
width 11) / 10 -
- // delegate the rest of the messages ...
-
17Using An ExpandingBall
- Heres how we might use an ExpandingBall in the
MultiBallWorld - protected void initializeArrayOfBalls( Color c )
- ballArray new MovableBall BallArraySize
- for (int i 0 i lt BallArraySize i)
- ballArrayi new ExpandingBall(
- new BoundedBall(
- 10, 15, 5, 3.0i, 6.0-i, this) )
- ballArrayi.setColor( ballColor )
-
18Do You Recognize a Pattern?
- We added flexibility and extensibility to our
system using the same ideas we used in previous
tw sessions combining composition and
inheritance. - substitution
- delegation
- recursion
- The new twist in this solution is that
DeceleratingBall and ExpandingBall use
substitution on a class in their own class
hierarchy! - This new twist is so common that it has its own
name decorator.
19- But heres a beautiful example of what using a
decorator can do for you - protected void initializeArrayOfBalls( Color c )
- ballArray new MovableBall BallArraySize
- for (int i 0 i lt BallArraySize i)
- ballArrayi new ExpandingBall(
- new DeceleratingBall(
- new BoundedBall(
- 10, 15, 5, 3.0i, 6.0-i, this)))
- ballArrayi.setColor( ballColor )
-
-
- Since a decorator is substitutable for instances
of its base class, you can decorate a decorator!
20How a Decorator Works...
21How a Decorator Works...
22The Decorator Pattern
- The Problem
- We would like to add a behavior to a set of
classes that share a common interface. - A Tempting Solution that Fails
- Use inheritance to create a new class of objects
that has the behavior. - Use instances of this class when you need the
behavior, and use instances of the superclass
otherwise. - This solution is impractical. Why?
- We will need to create multiple subclasses and
replicate the behavior in each. - What if we would like to add more behavior to the
extended object? We have to make (many!) more
subclasses!
23The Problem is Prevalent...
- Why Does This Problem Matter?
- It occurs in many domains and in many
applications - We want to add features to individual balls in
our ball games or to individual card piles in our
card games. - We want to add features to individual streams
in the Java library, such as buffering the input
we read from a stream. - We want to add windowing features to individual
objects in a word processor or drawing program.
24Java I/O Example of Combining Inheritance and
Composition
- An abstract concept of reading a stream of bytes
in sequence the class InputStream - Several concrete realizations that differ in
their data source - ByteArrayInputStream array of bytes
- FileInputStream external file
- PipedInputStream another process generates a
stream of bytes - SequenceInputStream
- ObjectInputStream
25Java I/O Example of Combining Inheritance and
Composition
- Each is declared as a subclass of InputStream, so
any can be substituted for type InputStream - Programs using InputStream can be written to
process a stream of bytes independent of the data
source
26Java I/O Example of Combining Inheritance and
Composition
- However, additional functionality thats
independent of the data source is often needed,
e.g., line numbers, buffering to allow rereading - These features are provided by defining a
subclass FilterInputStream of InputStream - FilterInputStream can hold an InputStream
component as its data source. - Therefore, its substitutable for InputStream and
can augment any type of data source - Example of a decorator (or filter or wrapper)
design pattern
27The Solution
- Create a decorator class.
- 1. Encapsulate an instance of the base class as
an instance variable of the decorator. - Implement the new behavior in the decorator.
Delegate as much of the new behavior to the
instance variable as possible. - Send all other messages recursively to the
encapsulated object. - 2. Use inheritance to extend the decorator class
from the contained class.
28How Does the Decorator Pattern Work?
- Inheritance creates substitutable classes. This
allows a decorated object to be used in all the
same places as the encapsulated object! - The superclass acts as an interface for all of
its subclasses.
29How Does the Decorator Pattern Work?
- An application wont knowor need to knowwhat
sort of MovableBall it is using the ball
responds to all the same messages. - Composition uses substitution to reuse the code
in the base class, but in a way that is
controlled by the decorator. - This allows us to add the same behavior to all of
the classes in the hierarchy!
30When to Use a Decorator?
- In a way, the decorator pattern allows us to add
new behavior to a single instance, rather than to
the whole class. - This works well whenever the new behavior is
orthogonal to the existing behaviors, that is, it
is related to the existing behaviors but does not
fit in the current way we break things up. For
example, we cant point to a particular place in
the Ball hierarchy and say, Thats where
deceleration belongs! Deceleration cuts across
the class hierarchy.
31When to Use a Decorator?
- Using a decorator makes sense any time there are
two varieties of some object, but the variations
are not directly related. - balls that bounce of the walls and balls that
decelerate - Would implementing BoundedBall as a decorator be
a good idea?
32Our Current Ball Hierarchy
- Both ExpandingBall and DeceleratingBall hold a
MovableBall as an instance variable. - Both ExpandingBall and DeceleratingBall respond
to messages by delegating the work to their
MovableBall.
33An Exercise
- public class DeceleratingBall extends MovableBall
- private MovableBall workerBall
- public DeceleratingBall( MovableBall aBall )
... - public void move() ...
- // MESSAGES DELEGATED TO THE INSTANCE
VARIABLE - public int radius() return workerBall.radius()
- public int x() return workerBall.x()
- ...
-
- public class ExpandingBall extends MovableBall
- private MovableBall workerBall
- public ExpandingBall( MovableBall aBall ) ...
- public void move() ...
- // MESSAGES DELEGATED TO THE INSTANCE
VARIABLE - ... // all the same delegation methods
-
- We have violated the Say it once and only once
rule!
34A common refacoring
35A Solution Use Inheritance
- 1Create a DecoratedBall class that implements
the behavior common to the two decorators - public class DecoratedBall extends MovableBall
- private MovableBall workerBall
- public DecoratedBall( MovableBall aBall ) ...
- protected MovableBall worker()
- return workerBall
-
- // DELEGATE ALL MESSAGES TO THE INSTANCE
VARIABLE! -
- public void move () workerBall.move()
- public Color color() return workerBall.color()
36A Solution Use Inheritance
- This class is just like the MouseAdapter class
that we studied earlier. It implements all of the
behaviors that a decorated ball needs by
delegating the message to its workerBall. - Programmers who want to implement a particular
kind of decorator do not have to implement these
default behaviors.
37Using the Solution Use Inheritance
- 2Implement each decorator class as a subclass
of DecoratedBall. For example - public class DeceleratingBall extends
DecoratedBall - public DeceleratingBall( MovableBall aBall )
- super( aBall )
-
- public void move()
- super.move()
- worker().setMotion( worker().xMotion() 0.95,
- worker().yMotion() 0.95 )
-
38Works great!
- All of the DELEGATED METHODS are inherited!
- Programmers that reuse the DecoratedBall class
can write only the methods that they need for
their applications. - Client code that uses DecoratedBall,
DeceleratingBall, and ExpandingBall cant tell
them apart from plain old MovableBalls.
39The Refactored Ball Hierarchy
40The Effect of the Decorator Pattern
- Notice how our new Decelerating- and
Expanding-Ball classes look just like the
original ones before using the Decorator pattern - From first solution last time (as a simple
subclass) - public class DeceleratingBall extends MovableBall
- public DeceleratingBall( int x, int y, int r,
double dx, double dy ) - super( x, y, r, dx, dy )
-
- public void move()
- super.move()
- setMotion( xMotion() 0.95, yMotion() 0.95
) -
41From solution today (as a subclass of the
decorator)
- public class DeceleratingBall extends
DecoratedBall - public DeceleratingBall( MovableBall aBall )
- super( aBall )
-
- public void move()
- super.move()
- worker().setMotion( worker().xMotion() 0.95,
- worker().yMotion() 0.95 )
-
-
42The Idea of Design Patterns
- When writing a program, you often face a problem
and think to yourself, What do I do now? - In object-oriented programming, that question
usually takes the form, What kinds of objects
should I create, and how should they communicate?
43The Idea of Design Patterns
- Then you stumble about looking for a solution.
Sometimes, you will create a good solution. More
often, your first few solutions will work just
well enough. Over time, you refactor the code in
the face of changing specs. As you go, you will
create better and better solutions. - After a while, you begin to recognize the same
problem showing up in different guises, so you
begin to know up front what sort of solution you
need.
44The Idea of Design Patterns
- Programming becomes easier as your experience
grows, because you recognize common problems and
know stock solutions for solving them.
45The Idea of Design Patterns
- A design pattern is simply a standard solution
for solving a common problem. - This solution is standard because all programmers
are trying to balance a common set of forces that
occur when we try to solve that class of problems.
46Some Design Patterns
- Chapter 7 starts a very brief catalog of
object-oriented design patterns common problems
and stock solutions for solving them. - Studying these patterns is a way for you to
increase your ability to program more quickly
than learning patterns by trial and error. They
also give you more and more examples of using
inheritance and polymorphism.
47Some Design Patterns
- So far in class, we have (or will shortly)
encountered a number of patterns including - Decorator decelerating balls, input streams
- Factory Method creating projectiles, ...
- Adapter MouseListeners and MouseAdapters
- Composite frames and panels in Swing AWT
- Strategy layout managers in Swing
- Substitution balls and pinball targets and
transactions and ... - Object Recursion binary tree methods
48Reading up on Design Patterns
- Check out the PDF I posted of non-software
examples of design patterns