1 In our last episode It was all about ObjectOriented Design 2 A Concise Theory of ObjectOriented Object represents a thing person car date not two things not ½ thing ID: 789734
Download The PPT/PDF document "Advanced OOD and the Strategy Pattern" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Advanced OOD and
the Strategy Pattern
1
Slide2In our last episode…(It was all about Object-Oriented Design)
2
Slide3A Concise Theory of Object-Oriented
Object represents a “thing”person, car, date, …(not two things, not ½ thing)Object responds to
messages(method calls)Things it does to itself (SRP)
That is, other objects ask the object to do something to itself
Objects are “opaque”
Can’t see each others’ data/
vars
Messages (calls) are only way to get things done
3
Slide4A Concise Theory of Object-Oriented, II
Because objects are completely opaque, we don’t need to know what’s really inside themEach car object could
be implemented with its own unique codeIf two cars behave the same, then really should have same codeOtherwise would violate DRY
And a huge amount of coding work
So all cars are made from a common car
template
Template = class
The car template is not a car, it’s a “blueprint” for a car
Helps satisfy
DRY
4
code
class
Slide5Single Responsibility Principle
Single Responsibility Principle (SRP)
Each class should be responsible for one thing(capability, entity, computation, etc.)Can phrase this as “mind your own business”
object do its own calculations
object should not do calculations for another
Easy to violate this because objects need to be connected to one another
e.g., Events happen as part of Dates
Slide6Object-Oriented Design, “wuggy style”
6
As a
user
I want
see my nearby friends on the map
So that
I know who to contact for a spontaneous meet-up
class Friend {
Location location(); // null −> not-known
boolean
online();
Bitmap image();
}
class Friends implements
Iterable
<Friend> {
Friends online();
Friends
locationKnown
(); // −> online?
}
Identify the “things”
me (previous user story)
friends, friend
map (previous, built-in)
Identify the messages
me.logged
-in (previous)
friend.location
-known
friend.location
friend.online
friend.near
(me)friend.image
Assemble into classesRight things call right messages (TBD)
Given
I am logged in
And
my location is known
When
my friends are online
And
my friends’ location is known
And my friends are near meThen I see them on the map
Slide7Object-Oriented TypingTheory of Object-Oriented, III
7
Slide8Typing and Subtyping: “is a”
In Object-Oriented, it’s all about behaviorA particular behavior is described by a typeMammalian behavior is the Mammal type
Tiger behavior is the Tiger typeBecause a Tiger always behaves like a Mammal, we say that Tiger is a subtype of Mammal
8
Mammal
Feline
Canine
Tiger
House Cat
Feline
is a
subtype
of Mammal
House Cat
is a
subtype
of Feline
s Subtype c
means all
s
’s
always act like a
c
but not all
c
’s
act like an
sAll Felines are Mammals
But not all Mammals are FelinesMeans that Feline object will always work wherever a Mammal is needed
Slide9Typing and Subtyping: “is a” (II)
Feline a subtype of Mammal means Mammal a supertype of FelineA supertype
variable can hold values of any of its subtypes
9
Mammal
Feline
Canine
Tiger
House Cat
void
petFur
(Mammal m) {
int
coarseness =
m.furValue
();
…
}
Use of a
supertype
variable like
Mammal
allows all current and future subtypes of Mammal to be petted
petFur
will work for
Canine
subclass
Dog
when it is added
We say that
petFur
is
open for extension
Slide10Three Ways to Declare Subtype in Java
Subclass a classclass Mammal {…}
class Feline
extends
Mammal {…}
Feline
is a
subtype
of
Mammal
Feline gets all of Mammal
’s implementation (can override)Subclassing abstract class is similarCan’t “new” an abstract C b/c not all methods implemented
abstract class
Mammal {…}class Feline
extends Mammal {…}Feline must implement missing methods of Mammal
Abstract class asserts “I’m a category of thing, not a real thing” Interface has no methods implementedLike a totally abstract class
interface Cuddly {…}
class HouseCat extends Feline
implements
Cuddly {…}
10
Mammal
Feline
Canine
Tiger
House Cat
Slide11More on InterfacesA class can extend just one superclass
But a class can implement multiple interfacesinterface Cuddly {…
}interface Spotted {…}
class
Tabby
extends
Feline
implements
Cuddly, Spotted
{…
}Means interfaces are much more flexible
Can “mix in” all the supertypes you wantNot just a tree of types anymore
11
Mammal
Feline
Canine
Bengal TigerTabby
Spotted Cuddly
Slide12More on Interfaces, II
Not all classes represent a unique typeMaybe want another impl of same thingfor performance, sayConsider two possible
impl’s of Setclass
TinySet
implements
Set { /* linked list */ }
class
BigSet
implements Set { /* uses hard disk */ }
Identical interfaces, input/output behavior −> same typeOne faster for tiny sets, the other faster for big setsUse interfaces for implementation alternatives
Since TinySet real subtype, extends would be misleading
Since no shared implementation, extends would be misleading12
Slide13How represent Feline (and Why)?
Class
Abstract ClassInterface
Extends
Abstract class allows reusing
some common implementation
among Felines, and yet cannot
be
new’d
(instantiated).
Interface is a reasonable
answer, too, as the sharing might
not be too great.13
Mammal
Feline
CanineTiger
House Cat
Slide14A Few Things to Remember
Avoid subclassing (extends)Use when you have a real type hierarchyAnd
when you are lazy and want to share method implementationsBut rare that non-leaf classes (like Mammal
) can be instantiated (
new
’d
)
Subclassing
abstract superclass is better
Captures “is-a” relationship of real type hierarchyPurpose is still to borrow method implementationsBut asserts that non-leaf class
can’t be new’dInterfaces are the bombThe most flexibleWhen you have multiple
supertypes, orWhen the subclasses are just implementation alternatives
14
Slide15Interfaces are Central to Java
Java Collections FrameworkInterface
Collectionmethods like add(Object)
&
contains(Object)
interface
List
extends
Collection …
interface
Set
extends Collection ……
Wherever Collection variable appears, allows for a a ListArray or
HashSet, etc.Requires no particularimplementationS
uper-flexiblecode15
Slide16Strategy PatternComposition + Delegation + Interfaces
16
Slide17Car Description: What’s Wrong?
abstract class CarDesc { Color
paintColor();
int
wheelbase();
…
int
tireSize();
boolean tirePerf();
String tireSeason(); /* should be enum
*/ }abstract class
SmallCar extends CarDesc { …
}class KiaSoul extends
SmallCar { …
int tireSize() {
return
165; }
boolean
tirePerf
() {
return
false; }
String
tireSeason() { return
“All”; }
CarDesc and maybe SmallCar should be an interfaceAll these classes should “implement” a Tire interface
KiaSoul should have a Tire fieldAs implemented,
KiaSoul only allows one set of values for tire behavior. By adding a Tire field and delegating to its function, then all sorts of tires will be possible. (See next slide.)“A” is an OK answer, but it’s not nearly as big a deal as the inflexibility of the tire methods.
17
Slide18“Strategy Pattern” Design
abstract class CarDesc { … }
abstract class SmallCar
extends
CarDesc
{
…
}
class
KiaSoul extends SmallCar {
Tire tires; … int
tireSize() { return tires.size
(); } boolean tirePerf() { return
tires.perf(); } String tireSeason
() { return tires.season(); }
KiaSoul has TiresDelegates tire method impls
to
Tire
Tire
impl
is reusable
in other
settings
Can change at runtime:
18
composes
Tire (“has-a”)
delegates
to Tire (easy!)
mySoul.changeTires
(new
DunlopSP
());
Slide19“Strategy Pattern” Design
abstract class CarDesc { … }
abstract class SmallCar
extends
CarDesc
{
…
}
class
KiaSoul extends SmallCar {
Tire tires; … int
tireSize() { return tires.size
(); } boolean tirePerf() { return
tires.perf(); } String tireSeason
() { return tires.season(); }
KiaSoul has TiresDelegates tire method impls
to
Tire
Tire
impl
is reusable
in other
settings
Can change at runtime:
Tire
should be a:
Class
Abstract class
Interface
Why?
We want to leave
KiaSoul open to having all kinds of tires, and an interface is most flexible. An abstract class is OK, too, if you think there is a Tire type hierarchy with significant shared implementation.
19
composes
Tire (“has-a”)
delegates
to Tire (easy!)
mySoul.changeTires
(new
DunlopSP
());
Slide20“Strategy Pattern” Design
abstract class CarDesc { …
}abstract class SmallCar
extends
CarDesc
{
…
}
class
KiaSoul extends
SmallCar { Tire tires; …
int tireSize() {
return tires.size(); } boolean
tirePerf() { return tires.perf(); }
String tireSeason() { return
tires.season(); }
20
<<interface>>
_____
Tire
_____
int
s
ize()
bool
p
erf
()String season()
_MichelinPilot_…
_
DunlopSP
_…
…
_____
KiaSoul
_____
Tire tires
_________
int
tireSize
()
bool tirePerf()String tireSeason()
I’m going to disagree
strongly
with the prior semester on this one.
MichelinPilot
and
DunlopSP
should be subclasses of Tire. Tire should not be an interface. The “is a “ relationship clearly holds and “acts like” is clearly too weak. Just because methods aren’t shared right at this second, doesn’t mean that they won’t be later. Design needs to be principled, not fit the moment. We shouldn’t put to an interface, just because the present requirements require no methods. We certainly can envision plenty. We’ll make a mess if we later need to add roll(), “
loseAir
()”, “
heatUp
()”,
etc
, methods, which would be implanted the same across all tires, and
T
ire is an interface not a base class.
Slide21Widely Used for Algorithm Alternatives
21
Slide22Take-Aways
Start thinking about objectsThen think about typesThen “is a” vs “has a”Then, consider the hierarchy
Are behaviors re-implemented because they don’t apply to all peer sub-types?Are behaviors appearing where they shouldn’t, or doing things they shouldn’t, by inheritance? Fix by overriding, if necessary
Better idea: Can the behaviors be moved down? An intermediary added?
Would pure abstract base classes be better served by interfaces [Java]?
Same behaviors, but not a common implementation
Behavior exhibited by other classes to which neither “as a” nor “is a” apply (just plain different classes)
Consider “is a” vs “has a” and then, as a refinement, “is a” versus “act like a”
22
Slide23That mysterious “Tracker” object
23
class Friend {
Location location();
boolean
online();
Bitmap image();
}
class Friends implements
Iterable
<Friend> {
Friends online();
Friends
locationKnown
(); // −> online?
}
Given
I am logged in
And
my location is known
When
my friends are online
And
my friends’ location is known
And
my friends are near me
Then
I see them on the map
Basic idea is an
intermediary
whose Single Responsibility is drawing my friends on the map
class NearbyFriendsTracker
{ private Friends
friends;
private GoogleMap map;
NearbyFriendsTracker(
GMap
map, Friends friends
)
;
void
showNearbyFriends
();
}Single responsibility
: drawing friends on map!
Don’t have to bunch of “extra” methods
Very similar, despite SRP
Still trying to make
code sounds like specification
Right things call right messages
Slide24UML Diagram: Middleman Design
24
_NearbyFriendsTracker_
-
GoogleMap
map
- Friends friends
−−−−−−−−−−−−−−−−−
+
showNearbyFriends
()
_________Friends_________- List<friend> friends−−−−−−−−−−−−−−−−−
+ Friends online()+ Friends locationKnown()
_
GoogleMap_…
_________Friend_________
+ boolean online()+ Location location()+ Bitmap image()
*
<interface>
_
Iterable
_
…
Our ten-cent OO Design theory did not account for this object.
But OO Design does
.
Nearby
is a
relationship
Does not “belong” to Friends or
GoogleMap
Active relationships
must be represented by a
separate object
like
NearbyFriendsTracker
Passive relationships can be represented by a separate object or a field/method
Slide25Theory of Object-Oriented, IV
25
_NearbyFriendsTracker_
-
GoogleMap
map
- Friends friends
−−−−−−−−−−−−−−−−−
+
showNearbyFriends
()
_________Friends_________- List<friend> friends
−−−−−−−−−−−−−−−−−+ Friends online()+ Friends locationKnown()
_
GoogleMap_
…_________Friend_________
+ boolean online()+ Location location()+ Bitmap image()
*
<interface>
_
Iterable
_
…
Identify the “things”
Identify the messages
Identify the relationships
Assemble “things” & messages into classes
Encode relationships into classes/methods that point at “thing” classes
Slide26Design PatternsNow experience doesn’t have to be a cruel teacher
26
Gang of Four
Slide27Rework the Design (UML OK)
class Operation { public int execute
(int a, int b) { return a + b;
}
class
Multiply
extends Operation {
public
int
execute(int a,
int b) { return fa * fb; }
}class Subtract extends Operation {…}class Divide
extends Operation {…}27
___
Operation___execute(int,int)
____Multiply____execute(int,int
)
_____Divide____
execute(
int,int
)
…
Apply the Strategy Pattern
Slide28What’s the problem with this design?
class Operation { public void execute(int
a, int b) { return a + b;
}
class
Multiply
extends Operation {
public void
execute
(
int a, int b) { return
fa * fb; }}class
Subtract extends Operation {…}class Divide extends Operation {…}
28
___Operation___execute(int,int
)____Multiply____
execute(int,int)
_____Divide____
execute(
int,int
)
…
Nothing, this is a good design
Use of
subclassing
Subclassing
is OK, but shouldn’t override methods
If I add a new method to Operation, may have to modify all the subclasses
Slide29It’s called extends!
If you’re not extending the class, bad signOccasional override OK if you’re also extending
But subclassing is not for alternatives For representing an actual type hierarchy
Multiply
and
Divide
are just alternatives, and
Operation
is placeholder: interface!
29
Mammal
Feline
Canine
Tiger
House Cat
Slide30Strategy Design
Interface OperationStrategy { public int
execute(int a, int b);
}
class
MultiplyStrategy
implements
OperationStrategy
{
public int
execute(int a, int b) { return fa *
fb; }}…
30
<<interface>>_OperationStrategy
_execute(int,int)
_MultiplyStrategy_execute(
int,int)
_
DivideStrategy
_
execute(
int,int
)
…
class
Calculate
{
private
OperationStrategy
opStrategy
;
public Calculate
(OperationStrategy os) { opStrategy
= os; } public
int execute(int a, int b) { return opStrategy.execute
(a, b); }}
___________Calculate
___________
_
Operation
Strategy_opStrategy
_
execute(
int,int
)
Calculate
composes
OperationStrategy
(“has-a”)
Calculate
delegates
to
OperationStrategy
Different implementations of same idea, not subclasses of general idea
Slide31What’s cool about strategy: runtime change
class Calculate { private
OperationStrategy opStrategy; public
Calculate
(Operation Strategy
os
) {
opStrategy
= os;
} public setStrategy(Operation
Strategy os) { opStrategy = os; }
public int execute(int a, int b) {
return opStrategy.execute(a, b); }}
public static void main(…) { Calculate calculator = new Calculator( new
MultiplicationStrategy()); System.out.println( calculator.execute(3,4));
/* 12 */ calculator.setStrategy( new
AdditionStrategy()); System.out.println( calculator.execute
(3,4
));
/* 7 */
31
Slide32Good-Enough Design Isn’t…Enough
Too slow, focused on a single object at a timeExperience can help us take big, fast leapsBut experience takes years to acquireDesign Pattern method is a shared vocabulary of software design experience
Focused on making softwarechange easierFocused on objectinteractions or relationships
Reduce “coupling”
Two things apart that have to change together
Two things together one has to change, other not
32
Slide33Design Pattern
A template for how to solve a problem that can be used in many different situations (wikipedia
)Each pattern solves a different design problemIdeally applied only when neededAnticipated from experience
Refactoring (typically from “problem” code to solution code)
If it
ain’t
broke, don’t fix it
Use of design patterns adds complexity
(and takes precious time!)
Cost vs. benefit
33
Slide34Agile and Always Runnable
If your app is running, you can confidently develop, test, debug, and demoIf it doesn’t run after adding new story, no fearRoll back, debug new code, etc.Failed tests, new bugs are due to new story
Narrows search, code still familiarCan demo your new story right awaySelf, teammates, customer
34
Slide35Always Runnable: How
User story is a “story” about a new thing that the user can do with appSo it should be demo-able, system testable, etc.Keep stories smallBut tendency is to make them too bigWrite a system test or two (or script them)
Make part of your “continuous integration”Don’t check in until system tests run
35
Slide36Always Runnable: Exercise
“The basic idea is that you can see you and all your instant-messaging buddies on a map, allowing you to message a nearby friend (say, to meet up at a local café).Let’s come up with a first “minimal” application (via User Story)Then a few extensions (more User Stories)
36
Slide37Minimal myCity
User can launch the application User can view a localized map
User can view themselves on a localized map See yourself on the map, and send a message to yourself
Create the chat and add one friend
37