30
Design Patterns MSO 08/09, WP

Design Patterns MSO 08/09, WP. Design pattern Client : “I want you to make a painting of our family.” Painter : “I can do various styles: realistic,

Embed Size (px)

Citation preview

Design Patterns

MSO 08/09, WP

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 ; }

Home work

Self-study these patterns (see online Resource) :

Few more simple patterns: bridge, proxy, abstract factory

The visitor pattern (advanced)

30