Thinkinking Objects
COMP 2511
Object Oriented Design &
Programming
1 © Aarthi Natarajan, 2018
Story so far,
Basic OO principles
Abstraction, Encapsulation, Inheritance, Polymorphism
Basic refactoring techniques
Extract method, Rename variable, Move Method, Replace
Temp With Query
This week
OO design principles
• Encapsulate what varies
• Program to an interface, not an implementation
• Favour composition over inheritance
Design Patterns
• Strategy and State Patterns
© Aarthi Natarajan, 2018 2
© Aarthi Natarajan, 2018 3
• A game that shows a large variety of duck species swimming
and making quacking sounds
• What we need is a base class Duck and sub-classes
MallardDuck, RedheadDuck for the different duck
species
A simple Duck Simulator App
© Aarthi Natarajan, 2018 4
• How hard can that be?
• Just add a fly() method to the class Duck and all sub-types
will inherit it
But, now we need ducks that fly
© Aarthi Natarajan, 2018 5
• A localised update to the code caused a non-local side effect
(flying rubber ducks)
• What normally is thought of as a great use of
inheritance for the purpose of “reuse” actually didn’t
turn out so well, when it comes to maintenance
Design Flaw…
© Aarthi Natarajan, 2018 6
• Solution 1:
– We could simply override fly() method to do nothing, just as the
quack() method was overridden
– But, what happens, when more different types of ducks were
added that didn’t quack or fly
Solution 1…
© Aarthi Natarajan, 2018 7
• Solution 2:
– Need a cleaner way, so that only some ducks fly and some
quack. How about an interface?
Solution 2…
© Aarthi Natarajan, 2018 8
• Using interfaces, all sub-classes that fly implement
flyable interface and that quack implement Quackable
interface
• But, completely destroys code reuse – every class must
implement fly() method (perhaps not an issue in Java 8),
but what if there are more than two kinds of flying
behaviour among ducks that fly.
• Change every class where behaviour has changed? –
maintenance night-mare
• Need a design pattern to come riding on a white horse
and save the day.
Solution 2…
© Aarthi Natarajan, 2018 9
• Is there a way to build software so that when we
need to change it, we could do so with the least
possible impact on the existing code?
© Aarthi Natarajan, 2018 10
• By separating what changes from what stays the same, the
result is fewer unintended consequences from code
changes and more flexibility in your software
• Another way to think about this principle: take the parts
that vary and encapsulate them, so that later you can alter
or extend the parts that vary without affecting those that
don’t.
Solution
Design Principle #3:
Identify aspects of your code that varies and
“encapsulate” and separate it from code that stays the
same, so that it won’t affect your real code.
© Aarthi Natarajan, 2018 11
So, let us pull out the duck behaviour from
the duck class
© Aarthi Natarajan, 2018 12
• How are we going to design the set of classes that
implement the fly and quack behaviour?
Design Principle #4:
Program to a an interface, not to an
implementation
© Aarthi Natarajan, 2018 13
• Program to an interface, really means “program to a
super-type” i.e., the declared type of the variable
should be a super-type (abstract class or interface)
– e.g., Dog d = new Dog(); d.bark(); // programming
to an implementation
– Animal a = new Dog(); a. makeSound(); //
programming to an interface
• What we want is to exploit polymorphism by
programming to a super-type so that actual run-time
object isn’t locked into the code
© Aarthi Natarajan, 2018 14
Previously,
– A behaviour was locked into a concrete implementation in the
Duck class or a specialised implementation in the sub-class
– Either way, we were locked into using a specific
implementation
– There was no room for changing that behaviour
Now,
– Use an interface to represent the behaviour
– Implement a set of separate “behaviour” classes that
implement this interface
– Associate a duck instance with a specific “behaviour”
class
– The Duck classes won’t need to know any of the
implementation details for their own behaviour
Programming to a super-type
© Aarthi Natarajan, 2018 15
Implementing the Behaviours
Here, there are two interfaces, FlyBehavior and QuackBehavior along with set of
classes that implement each concrete behaviour
© Aarthi Natarajan, 2018 16
Integrating Duck behaviour with the Duck instance
1. Define two instance variables in the Duck class
2. Implement performQuack() and performFly() that delegate the quacking and
flying behavior to other objects
3. Assign the instance variables the right behavior
© Aarthi Natarajan, 2018 17
Setting behaviour dynamically
1. Create two setter methods setFlyBehavior() and
setQuackBehavior() inside class Duck
2. To change a duck’s behavior at run-time, call the duck’s setter
method for that behavior
public abstract class Duck {
…
// Add setter methods to change behavior at run-time
public void setFlyBehavior(FlyBehavior f) {
this.flyBehavior =f ;
}
public void setQuackBehavior(QuackBehavior q) {
this.quackBehavior = q;
}
}
© Aarthi Natarajan, 2018 18
Our complete design
Think about the different relationships – IS-A, HAS-A, IMPLEMENTS
HAS – A
IS – A
IMPLEMENTS
© Aarthi Natarajan, 2018 19
• Each duck has a fly behaviour and has a quack behaviour.
Haven’t we heard of this relationship?
COMPOSITION
• Instead of inheriting their behaviour, the ducks get their
behaviour by being composed with the right behaviour
objects and delegate to the behaviour objects
• This allows you to encapsulate a family of algorithms
• Enables you to “change behaviour” at run-time
HAS-A can be better than IS-A
Design Principle #5:
Favour composition over inheritance
© Aarthi Natarajan, 2018 20
• We have just applied our first design pattern to design our
Duck app
STRATEGY PATTERN
• This allows you to encapsulate a family of algorithms
• Enables you to “change behaviour” at run-time
Our first design pattern
Design Pattern #1: Strategy Pattern
This pattern defines a family of algorithms,
encapsulates each one
© Aarthi Natarajan, 2018 21
• A design pattern is a tried solution to a commonly
recurring problem
• Original use comes from a set of 250 patterns
formulated by Christopher Alexander et al for
architectural (building) design
• Every pattern has
– A short name
– A description of the context
– A description of the problem
– A prescription for a solution
Design pattern
© Aarthi Natarajan, 2018 22
• In software engineering, a design pattern is a general
repeatable solution to a commonly occurring
problem in software design
• A design pattern is
– Represents a template for how to solve a problem
– Captures design expertise and enables this
knowledge to be transferred and reused
– Provide shared vocabularies, improve
communications and eases implementation
– Is not a finished solution, they give you general
solutions to design problems
Design pattern
© Aarthi Natarajan, 2018 23
Using Design Patterns is essentially an “art &
craft”
• Have a good working knowledge of patterns
• Understand the problems they can solve
• Recognise when a problem is solvable by a
pattern
How to use Design Patterns?
© Aarthi Natarajan, 2018 24
• Behavioural Patterns
• Structural Patterns
• Creational Patterns
Design Patterns Categories
© Aarthi Natarajan, 2018 25
• Motivation
– Need a way to adapt the behaviour of an algorithm at
runtime
• Intent
– Define a family of algorithms, encapsulate each one, and
make them interchangeable
– Strategy pattern is a behavioural design pattern that lets the
algorithm vary independently from the context class using it
Pattern #1: Strategy Pattern
© Aarthi Natarajan, 2018 26
27
Image http://www.oodesign.com/
Strategy Pattern: Implementation
© Aarthi Natarajan, 2018
• Applicability
– Many related classes differ in their behaviour
– A context class can benefit from different variants of an
algorithm
– A class defines many behaviours, and these appears as
multiple conditional statements (e.g., if or switch). Instead,
move each conditional branch into their own concrete
strategy class
• Benefits
– Uses composition over inheritance which allows better
decoupling between the behaviour and context class that
uses the behaviour
• Drawbacks
– Increases the number of objects
– Client must be aware of different strategies
Strategy Pattern: Uses, Benefits, Liabilities
© Aarthi Natarajan, 2018 28
• Sorting a list (quicksort, bubble sort, merge-sort)
₋ Encapsulate each sort algorithm into a
concrete strategy class
₋ Context class decides at run-time, which
sorting behaviour is needed
• Search (binary search, DFS, BFS, A*)
29
Strategy Pattern: Examples
© Aarthi Natarajan, 2018
Next,
– State Pattern
– Revisit our video rental example
© Aarthi Natarajan, 2018 30
• A movie can change its classification during its life-time,
hence the price of the movie would vary
• The design above is not right, for the same reason we
cannot have fly() inside the Duck class
Recall our Video Rental Example from Week 03
© Aarthi Natarajan, 2018 31
• Remember our design principles
– encapsulate what varies
– compose and delegate
• Refactoring Techniques that support these principles
– Replace Type Code with Strategy/State Pattern
– Replace conditional logic with polymorphism
• Sadly, it has one flaw…a movie can change its classification
during its life-time
© Aarthi Natarajan, 2018 32
Summary
• Knowing OO basics does not make you a good
OO designer
• Good OO designs are reusable, extensible and
maintainable
OO Basics
• Abstraction
• Encapsulation
• Inheritance
• Polymorphism
OO Principles
• Principle of least
knowledge – talk only to
your friends
• Encapsulate what varies
• Favour composition over
inheritance
• Program to an interface,
not an implementation
OO Patterns
• Strategy
• State
© Aarthi Natarajan, 2018 33