Upload
louise-stokes
View
218
Download
3
Embed Size (px)
Citation preview
Design pattern
Client : “I want you to make a painting of our family.”
Painter : “I can do various styles:
realistic, impressionistic, abstract.
Which one do you want ?”
Design pattern : pattern for solving a repeating problem. Rigid, as in “map” in Haskell Loose, as we will discuss here
2
Design patterns in software engineering
OO is one hand very expressive!
But it also overwhelms us with lots of options to solve the same problem.
3
Novice developer:
• have to make the choice • may make a wrong choice• will re-invent lots of solutions
Expert developer:
• know lots of solution patterns from experience• re-apply patterns to solve next problem
Software architect’s bible
4
Documenting 23 useful design patterns, learned from experience.
“Gang of Four” (GOF)
Our plan today
Discuss some of GOF’s patterns.
There is 1x assignment to help you understand them.
Unfortunately, we have no time for actual programming
I recommend (this is your own activity, not assignment):
write a proto-implementation of your solution in Java buy GOF’s book, and apply it when you have to work on your Java
projects.
5
Where are we ? UML is very generic, you can use it to model things at
various levels
6
Design Implementation
Person
Doctor Patient0..*Doctor Patient0..*
PatientState
Example
Problem:
I need a class “God” that can only have 1 instance.
Motivation:
A God-object can do powerful things; one God-object is sufficient.
For security I need to guarantee that there is indeed only one God-object, implying that it would be sufficient for me to monitor this single God.
Solution ??
7
Solution
8
God
- i : God - God() + God getInstance()
God
- i : God - God() + God getInstance()
class God {
… // fields and other methods here
private God() { ... } ;
static private God i = new God() ;
public static God getInstance() { return i ; } }
Singleton
- i : Singleton - Singleton() + Singleton getInstance()
Singleton
- i : Singleton - Singleton() + Singleton getInstance()
pattern !
Singleton Pattern
Problem: salary administrator
A salary administrator is responsible for calculating yearly bonus of employees.The algorithm to calculate this differs depending on an employee’s function.
Direct solution:
9
Class SalaryAdminstrator { … calcBonus() { for (Employee e : elist) if (e.function == PROFESSOR) e.bonus = 0 else if (e.function == LECTURER) e.bonus = 1.9 * e.salary else e.bonus = 1.1 * e.salary } …
List<Employee> elist
Solution : exploit subclassing
10
Class SalaryAdminstrator { … calcBonus() {
} …
for (Employee e : elist) e.calcBonus()
Employee
…+ calcBonus()
Professor
…+ calcBonus()
Lecturer
…+ calcBonus()
Secretary
…+ calcBonus()
salarybonus
calcBonus() { bonus = 1.9 * salary }calcBonus() { bonus = 0 }
Strategy Pattern
11
Strategy
…+ calc()
StrategyA
…+ calc()
StrategyB
…+ calc()
StrategyC
…+ calc()
Client
1
0..*
What are the main guidelines ?? Modularity !
ExtensibilityWe should be able to extend a software without ‘changing’ the existing code.
ReusabilityWe should avoid replicating the same functionalities error prone, and higher maintenance cost.
On the other hand, balance this with coupling/dependency
Increasing the coupling also makes a software more error prone, and increases maintenance cost.
12
Problem : tables
A program wants to calculate the number of cells that a given table has.A table consists of rows. Each row consists of cells, and may be of different length.
Direct solution :
13
Table
Row
Cell
rows
cells
0..*
0..*
class App { ... numCells(Table t) { int i = 0 ; for (Row r : t.rows) for (Cell c : r.cells) i++ ; return i ; }
A nicer solution
14
Table Row
Cell
children0..*Component
Composite
+ numOfCells() : int
class App { ... numCells(Component c) { return c.numOfCells() ; } ...
Now "App" can just look like this :
numOfCells() { int k = 0 ; for (Component c : children) k = k + c.numOfCells() ; return k ;}
numOfCells() { return 1}
"Composite" Pattern
15
Cell
+ operation()
children0..*
Component
+ operation()
Composite
+ operation()+ add(Component c)+ remove(Component c)+ getChildren() : List<Component>
Client
Pattern classification (GoF)
Creational patterns Singleton Factory Method, Abstract Factory
Structural patterns Composite Bridge, Proxy
Behavioral patterns Strategy, Observer, Template Method, Visitor (?)
16
Problem: live charts
17
A=10B=40C=30D=20
A
BC
D
A DCB
This picture is taken from A.P. Mathur, slides "Design Patterns", CS 406 Software Engineering I, Purdue Univ. 2001.
• We want to display this data in various charts.• There is a controller active that works on the data.• We want the change to be mirrored “live” in the charts.
controller
Let’s look at similar but simpler problem
18
Heater
Celcius displayFahrenheit display
Controller
class Heater {
int temp ; Thermometer ct ; Thermometer ft ; ... void change(int d) { temp = temp + d ; ct.update(temp) ; ft.update(9*temp/5 + 32) }
}
Solution
19
Make it so that we can add/remove thermometers.
class Heater { private int temp ; public List<Thermometer> ts ; ... void change(int d) { temp = temp + d ; notify() ; }
public void notify() { for (Thermometer t : ts) t.update(this) }}
We can add/remove Thermometer to this list.
Here is where we will put the temperature conversion.
Solution
20
Thermometer
- temp : int
+ update(Heater)
CelciusThermometer FahThermometer
update(h) { temp = h.temp }
update(h) { temp = 9*h.temp/5 + 32 }
Heater
- temp : int
Subject
+ add(Thermometer)+ remove(Thermometer)+ notify()
oberservers
0..*
Observer Pattern
21
Observer
+ update(Subject)
ConcreteObs1 ConcreteObs2ConcreteSubject
Subject
+ add(Thermometer)+ remove(Thermometer)+ notify()
oberservers
0..*
MVC Model View Controller : a variant of Observer Pattern
22
Observer
+ update(Subject)
Subject
+ add(Thermometer)+ remove(Thermometer)+ notify()
0..*
Controller
(View) usually GUI(Model)
Problem
I need different kinds of thermometers, but the decision can only be done at the run time.
23
class Panel {
Themometer t ; ... public Panel(Class tkind) {
if (tkind == CelciusThermometer.class) t = new CelciusThermometer()
else if (tkind == FarThermometer.class) t = new FarThermometer()
else ... // error ! ... }}
Solution : Factory Method pattern
24
public Panel(Class tkind) {
t = ThermometerCreator.factoryMethod(tkind) ... }
ThermometerCreator
+ factoryMethod (Class) : Thermometer
static public factoryMethod(Class tkind) {
if (tkind == CelciusThermometer.class) return new CelciusThermometer()
else if (tkind == FarThermometer.class) return new FarThermometer()
else ... // error !}
Problem
I need a method that calculates the max element of two lists.
25
class MyClass {
private Comparable max(List<Comparable> s) ...
Comparable max2(List<Comparable> s, List<Comparable> t) { m1 = max(s) ; m2 = max(t) ; if (m1==null && m2==null) return null ; if (m1==null) return m2 ; if (m2==null) return m1 ; if (m1.compareTo(m2) > 0) return m1 else m2 ; }}
if (s.isEmpty()) return null ;
m = s.get(0) ;
for (k : s) if (k.compareTo(m) > 0) m=k
return m ;
Solution
26
abstract class TemplateSolution {
abstract Comparable max(List<Comparable> s)
Comparable max2(List<Comparable> s, List<Comparable> t) { m1 = max(s) ; m2 = max(t) ; ... // as before }
TemplateSolution
# max+ max2
Solution1
Solution2
max(s) { // as before }
max(s) { return s.get(0) }
Template Method pattern
27
TemplateSolution
# operation1(...) # operation2(...)...+ templateMethod(...)
ConcreteSolution1
ConcreteSolution2
• The template method specifies an algorithm over the operations.• Each concrete solution implements or overrides the operations.
• Keep in mind that this also increases the coupling if these operations may only be used in the way they're used by the template method.
Folding over a structure
I want to write methods to: count the sum of all cells in a component return me the cell with the max value
28
Cellvalue : int
children
0..*Component
Composite
Direct solution & Visitor Pattern
We have to keep writing the recursion over the structure of Component!
Can't we get a fold-like solution here?? Yes, with the Visitor Pattern.
29
sumCell (Component u) {
if (u instanceof Cell) return u.value ;
Composite u_ = (Composite) u ; int k = 0 ; for (Component v : u_.children) k = k + sumCell(v) ; return k ; }