CS 441: Bridge and Abstract Factory

advertisement
CS 4240: Bridge and
Abstract Factory
Readings:
 Chap. 10 and 11
Let’s Recap Some Ideas
and Strategies
We’ll assume some designplanning is useful up-front
Design with change in mind
Change will happen
Not sure exactly what it will be
Can predict in advance where it’s
likely to happen
Outline
First, factory patterns
Then, Bridge pattern
Factories
What’s a factory?
An object whose responsibilities are
creating one or more objects for
clients
Why bother? Why not let client
create its own instances?
What do you think?
Design Goal of Factories
Sometimes we can separate knowledge
of “how to use” from knowledge of
“what exactly to create”
Client knows first part, factory second part
Abstract class (or interface) vs. object
implements that interface
Program to abstractions
Encapsulate what varies
Factory provides objects that meet
interface but client doesn’t know
concrete class of that object
Reminder: Static Factory
Method
Static factory method
Coding technique
Class-level method, returns an
instance
Question: what design pattern relied
on this
Hint: like factories, also a creational
pattern (a design pattern responsible for
creating objects)
Remember Singleton?
Example code:
GameMaster gm =
GameMaster.getInstance();
Note here a class-level operation
returns an instance
Not a separate factory object
Factory Method Pattern
Our book doesn’t mention this one, but
it’s easy
GoF book intent:
Define an interface for creating an object,
but let subclasses decide which class to
instantiate. Factory Method lets a class
defer instantiation to subclasses.
Client uses reference to a factoryinterface to get an object it needs
Document Processing Example
 Client gets
factory object
 Asks factory for
document
 Factory
provides some
instance
 Client doesn’t
know exactly
what subtype
 How does
factory know?
Choices and Factories
Might be one factory object that can
create different types of objects
Client passes a string or some identifier
Comments on this kind of design?
(Coupling?)
Often more than one kind of factory
object
How does client get one? Ideas?
Choices and Factories (cont’d)
Somehow client gets a factory object
Sometimes a static method provides
this
DocFactory df =
DocFactory.getFactory();
Note: DocFactory will be abstract class here
How does that method know?
One option: stored in configuration file
or Java property
Bottom line: some factor decides, and
it’s “bound” to the client somewhere.
What makes sense? Best coupling?
Example: XML parsing
XML documents
Many parsers available, different
strategies, many options for
parsing
SAXParser is a standard interface
JAXP: an API but not a parser
Libraries provide parsers that work
with it
Code sample
 Typical use:
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setValidating(true); // factory properties
DocumentBuilder builder =
factory.newDocumentBuilder();
Document doc = builder.parse(aDocFile);
 How is parser set? Java properties
Abstract Factory
Intent from GoF:
Provide an interface for creating families of
related or dependent objects without
specifying their concrete classes
Same idea as before
Separate responsibilities of what-to-create
from how-to-use
Difference: families of related objects
Possible Examples
GUIs for multiple platforms etc
Button, Label, etc.
Different implementations, but all need to
be the same “family”
XML docs
Nodes, labels, children
Same operations but different parsers may
produce different versions
What would make this approach work?
What’s common between families?
The Abstract in Abstract
Factory
In this pattern, the factory creates
objects called “products” for a common
family
Family could change
What doesn’t change:
Each product meets an abstract interface
E.g. Button is an abstract class, and all
versions meet that
So client references products as
abstractions
Same Ole Song, No?
What varies:
Family defined differences between,
say, two kinds of button
So encapsulate this variation
Also, what varies is choice of family
Sometimes this, another time that
Encapsulate what-to-create inside
Factory object
Textbook’s Example
Client works with a computer’s
drivers.
Depending on computer, uses:
High Resolution Display Driver and
High Resolution Printer Driver
-- OR -Low Resolution Display Driver and
Low Resolution Printer Driver
You Know to Do This
 Application programs to interfaces
 But how to make sure always using consistent
objects in one family?
Use vs. Create
Client could take full responsibility for
creating objects
Switch on “selection-factor”
Creating a bunch of things from one family
Now client is less cohesive
Coupling: If more families added, family
details change, client must change
Abstract Factory Solution
Take what we learned from Factory
Method pattern
An object is responsible for creating things
for a client to use
But now:
create many different products (e.g. Button,
Label, TextField, etc.)
Have one interface for creating all these
Client gets and uses an instance of the
Factory object to create things
Sequence of Events
Make sure you understand the
order of events
Client gets a factory of type
ResFactory
Which one? How does it know?
Calls methods in this ResFactory
objects to get products it needs
Uses these references to products
Abstract class or interface
Choice of Factory
Again, how does the client choose one
factory? Where?
Might have a line of code to get a specific
one:
ResFactory factory = new LowResFact();
Might be in a configuration file
Class-level method in ResFactory
Other possible ways (user pref, cookie,…)
But: one place to change this!
“One rule, one place”
General Form
Our Book Points Out…
Adaptors often used here to make
concrete products fit
AbstractProduct interface
Switches (or decisions) still here
probably, just moved to one place
Summary
Division of responsibilities
How to use (client needs to know)
What to create
If abstraction used, client doesn’t need
to know
Hand off responsibility to factory
object
Coupling of client to family-details
reduced greatly
Bridge Pattern
GoF book’s intent says:
De-couple an abstraction from its
implementation so that the two can vary
independently
Implementation here means:
Not the concrete class that implements an
abstraction
Instead, the logic or code that makes the
hard work happen
Assume this is in a helper-object
CVA yada yada yada…
What varies here?
First, we have the usual abstraction
hierarchy of IS-A’s
Second, we have multiple ways work gets
done (implementations)
These need to be combined
Plan:
Encapsulate what varies
Prefer aggregation to inheritance
But inheritance is in here too
Don’t use inheritance to combine across
dimensions of variation
Book’s Example
Client wants to draw shapes
Has two drawing programs (engines)
Keep possibility of using either one
But shapes know which, and client doesn’t
Drawing programs may have different
interfaces for drawing primitives
Book’s Example
Shapes
Rectangle, Circle, ...
Two drawing "programs" or components
We need two versions of each Shape
One uses DP1, the other DP2
“Implementation” here means:
the drawing component used for a given
Shape object
What Might Vary and
Where?
Drawing programs
Different methods for primitive drawing
operations
draw a line, draw a circle
Shapes
Rules for drawing a rectangle does NOT vary
four lines between corners
So this logic belongs in abstract Rectangle
class
UML for Shape Hierarchy
Linking in the DPs
Note four concrete classes
2 Shapes x 2 DPs = 4 variations
The “V1 versions” must use a DP1
object
E.g. for V1Rectangle, drawLine() calls DP1’s
draw-a-line method
So a DP1 object linked to V1Rectangle
See sequence chart, p. 166
Note only 3 objects at run-time:
client, someV1Rectangle, theDp1
What’s the problem(s)?
Explosion of classes
For each variation of shape, multiply
that by variation in DP
Coupling
Every concrete class needs to know
its family
Improvement (?)
Have an abstraction based on
shape-type
Abstract class: V1Shape
Move link to particular DP up there
See next UML diagram
Better? Problem(s)?
Class explosion still here
Hard to see since 2+2 == 2x2
But another DP? 6 concrete classes
Or another Shape? 6 concrete classes
Redundancy
Both V1Rectangle and V2Rectangle
have logic of how lines are used to
form a rectangle
The Overall Problem
Need to decouple two abstractions
Shape (domain object hierarchy)
Drawing program (implementation)
Both vary
Independently
Use aggregation for this
coupling/link/relationship
Once again:
Aggregation separates single “thing”
into two components
More Details
Two Abstractions in the Bridge
Comments on Bridge
Again, note what’s meant by
“implementation” here
What a class needs to carry out the job
Note Rectangle and Circle are now
concrete classes
Rules for how-to-draw-myself are here
One rule, one place! (See p. 179)
Note V1Drawing and V2Drawing (bad
names?) are concrete classes
Quiz! What pattern is Drawing, V1Drawing,
and DP1?
Comments on Bridge (2)
How does link/connect between a
Shape object and a particular Drawing
get made?
E.g. someRectangle uses V1Drawing object
Client must make this happen
What if clients wants lots of shapes,
each using same DP?
Have we seen a pattern to help us here?
Answer:
Real Examples
Device drivers (e.g. printer
drivers)
Various types of printer with
variations
B&W, duplex, paper control
Various implementations for
particular hardware
JDBC: Java to SQL DB driver
AWT Windows
Summary
See book for other comments
Important point about Bridge
Decouple two abstractions that can
vary simultaneously
One uses the other to implement
functionality
Avoid explosion of subclasses, poor
coupling, redundant code
Often used with other patternsß
END
Download