41
Design Pattern 2 [FF 6 – 11]

Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

Embed Size (px)

Citation preview

Page 1: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

Design Pattern 2[FF 6 – 11]

Page 2: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

2

Remember Starbuzz Coffee?

Coffee instruction1. Boil water2. Brew coffee in boiling water3. Pour the mix in cup4. Add sugar and milk

Tea instruction1. Boil water2. Put tea leaves in boiling water3. Pour the mix in cup4. Add lemon

CoffeeboilWater()brewCoffee() pourMix()addSugarMilk()prepare()

TeaboilWater()brewTea() pourMix()addLemon()prepare()

prepare() { boilWater() brewCoffee() pourMix() addSugarMilk()}

Can we improve this design?

Page 3: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

3

Factor out common things to a superclass

CoffeebrewCoffee() addSugarMilk()prepare()

TeabrewTea() addLemon()prepare()

<<abstract>>HotBeverageboilWater()pourMix()prepare() // abs

prepare() { boilWater() brewCoffee() pourMix() addSugarMilk()}

prepare() { boilWater() brewTea() pourMix() addLemon()}

What else can be improved?

prepare() { boilWater() brew () pourMix() addCondiments()}

you can even finalize it

Page 4: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

4

The new design

Coffeebrew() addCondiments ()

Teabrew() addCondiments()

<<abstract>>HotBeverageboilWater()pourMix()prepare()brew()addCondiments()

“prepare” is no longer

abstract!

final prepare() { boilWater() brew () pourMix() addCondiments()}

So how easy is it now to add Chocolate??

The method “prepare” is a so-called “template method”; “brew” and “addCondiments” are called “hooks”. So this “pattern” here is called “Template Method Pattern”.

Page 5: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

5

Another example

public class MyApplet extends Applet {

public void init() { start to pre-load that film! load main image repaint() }

public void stop() { if film is playing, stop it }

public void start() { continue film }

public void paint() {...}}

These are hooks, used by a number of template methods in the superclass Applet.

Page 6: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

6

Generic remote control

• We need to design this generic RC for HomeAutomation Inc• Slots must be dynamically assignable• HA provides a bunch of “devices”• Unfortunately they have varying interface• Furthermore ... expect more devices will come in the future

RemoteControlslots : Device[8]assignSlot(slotNr,device)turnOn(slotNr)turnOff(slotNr)undo()

OutdoorLightturnOn()turnOff()

StereoturnOn()putcd()setvolume(v)turnOff()

CeilingFanlow()medium()high()off()getSpeed()

Device

Page 7: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

7

First solution

• Behavior that dynamically depends on subtypes• Remember the Factory solution ?• We need to do something similar, but with dynamic behavior

selection. • (this presentation deviates a bit from FF)

RemoteControlslot : Device[8]assignSlot(slotNr,device)turnOn(slotNr)turnOff(slotNr)undo()

turnOn(n) { d = slot[n] if d is an OutdoorLight then d.turnOn() else if d is a Stereo then { d.turnOn() d.putCD() d.setVolume(10) } else ...}

Page 8: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

8

Encapsulating ...

We encapsulate each “sub-type” of behavior in its own “Command” class.

RemoteControlonCmds : Command[8]offCmds : Command[8] assignSlot(slotNr,device)turnOn(slotNr)turnOff(slotNr)undo()

Device LightOnCmd

Commandexecute()

LightOffCmd

StrereoOnCmd

StrereoOffCmd

our “behavior factory method” :

assignSlot(n,device) { onCmds[n] = device.createOnCmd() ; offCmds[n] = device.createOffCmd() ; }

turnOn(n) { onCmds[n].execute() }

turnOff(n) { offCmds[n].execute() }

Page 9: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

9

How client requests are now handled..

DeviceOutdoorLightOnCmd

Commandexecute()

OutdoorLightOffCmd

StrereoOnCmd

StrereoOffCmdexecute() { d = (Strereo) device d.turnOn() ; d.putCD() ; d.setVolume(10)}

execute() { d = (OutdoorLight) device d.turnOn() ;}

:RC

turnOn(1)execute() turnOn()

putCD()setVolume(10)

:Command :Device

OutdoorLightOnCmd OutdoorLight

Page 10: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

10

Adding Fan-commands and Undo

DeviceOutdoorLightOnCmd

Commandexecute()undo()

OutdoorLightOffCmd

FanOnCmd

FunOffCmd

execute() { d = (CeilingFan) device speed = d.getSpeed() if speed is 0 then d.low() else if speed is low then d.medium() … oldstate = speed}

undo() { (OutdoorLight) device . turnOff() }

FanCmdoldState

undo() { d = (CeilingFan) device if oldstate is off then d.turnOff() else if oldstate is low then d.low() ... }

Page 11: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

11

Now implementing “undo” on the RC ...

RemoteControlonCmds : Command[8]offCmds : Command[8] assignSlot(slotNr,device)turnOn(slotNr)turnOff(slotNr)undo()- lastCmd : Command

turnOn(n) { c = onCmds[n] c.execute() lastCmd = c}

undo() { lastCmd.undo() lastCmd = new DoNothingDevice()}

Page 12: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

12

The “Command Pattern”

Receiveroperation1operation2

Concrete Cmd 1<<interface>>Commandexecute()undo() Concrete Cmd 2

Invoker

Client

<<create>>

Device

RemoteControl

Encapsulate behavior as an object; like normal object, these objects can be e.g. grouped together, send, and manipulated, before we execute the behavior they represent.

(different formulation than FF)

Device

Page 13: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

13

Example of things you can do

• You can stream commands, and have multiple threads consuming them

• logging and reload useful when the “invoker” crashes

MacroCmdcmds : Command[]execute()undo()

execute() { for (i=0; i<#cmds; i++) cmds[i].execute()}

undo() { for (i=#cmds; 0<i; i--) cmds[i-1].undo()}

Page 14: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

14

The merging of 3 restaurants...

• They can agree on a common class for “menu item”• But refuse to change how the menus are internally represented too

much of their respective software already depend on it

MenuItemnamedescisVeggieprice

DinnerMenumenu : MenuItem[]addItem(item)

PancakeHouseMenumenu : ArrayListaddItem(item)

CafeMenumenu : HashTableaddItem(item)

MenuWebInterfaceprintFullMenu()printVeggies()printLowBudget()

*

*

*(“Waitress” in your book)

Page 15: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

15

Let’s now implement the MenuWebInterface …

printFullMenu() { dinnerItems = dinnerMenu.items // array for (i=0; i<dinnerItems.size; i++) print (dinnerItem[i]) lunchItems = pancakeHouseMenu.items // listarray for (i=0; i<lunchItems.size(); i++) print ((MenuItem) lunchItems.get(i))

drinks = cafeMenu.items.getValues() // values of hash-table for (i=0; i<drinks.size(); i++) print ((MenuItem) drinks.get(i))}

Similar iterations in implementing the other print operations

Page 16: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

16

Encapsulating iterationsDinnerMenu- menu : MenuItem[]addItem(item)

PancakeHouseMenu- menu : ArrayListaddItem(item)

<<interface>>IteratorhasNext() : boolnext() : Object

MenugetName()createIterator()

<<create>>

(deviate a bit from FF)

// you can hide it now

DinnerMenuIterator

PancakeMenuIterator class DinnerMenuIterator extends Iterator { MenuItem[] items int ctr

DinnerMenuIterator(items) { this.items = items ; ctr = -1 }

hasNext() { return ctr < #items - 1 } next() { ctr++ ; return items[ctr] }}

createIterator() { return new DinnerMenuIterator(menu)}

Iterator pattern

(abs. class)

Page 17: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

17

Reworking MenuWebInterfaceMenuWI

<<interface>>MenugetName()createIterator()

* menus

printMenu() { for (Menu m : menus) { print m.getName() iter = m.getIterator() while (iter.hasNext()) { i = (MenuItem) iter.next() ; print(i) ; }}

: MenuWI : DinnerMenu

: DinnerMenuIterator

printMenu()createIterator() <<create>>

hasNext()

next()

etc …

Page 18: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

18

Iterator in Java

• Using the pattern amounts to subclass it• Standard collection classes already come with their iterator-classes.• “remove” is optional. It removes the element the element you just get from next() ; can

only be called once per next() call.• if you change the underlying ‘collection’ during an iteration by any other way than using

remove(), the behavior of the Iterator is undefined.

<<interface>>IteratorhasNext() : boolnext() : Objectremove() : void

Java.Util.Interface

i = V.iterator() ;while (i.hasNext()) { x = i.next() ; if (x == Bob) V.add(Patrick) ; print(x) ;}

// will Patrick be printed ?

Page 19: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

19

While we are talking about Java iterators...

<<interface>>IteratorhasNext() : boolnext() : Objectremove() : void

<<interface>>EnumerationhasMoreElements() : boolnextElement() : Object

Before Java 1.2 :

Suppose we have Java 1.1 legacy code; new features are to be added in 1.6. In the new part we prefer to use Iterator; but how to upgrade your old Enumeration classes to Iterators?

EnumerationAdapterconstructor(enumeration)

1.6Client

<<use>>1

Concrete EnumerationA

Page 20: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

20

Implementation

<<interface>>IteratorhasNext() : boolnext() : Objectremove() : void

<<interface>>EnumerationhasMoreElements() : boolnextElement() : Object

EnumerationAdapterenumconstructor(enumeration)

1.6Client

<<use>>1

Concrete EnumerationA

EnumerationAdapter(e) { enum = e }

enum

hasNext() { return enum.hasMoreElements() }next() { return enum.nextElement() }remove() ...??

For client now to iterate over A :

e = instanceA.getEnum()i = new EnumerationAdapter(e)

AgetEnum() : ConcreteEnumerationA

Page 21: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

21

That was the “adapter pattern”

Targetoperations

Adapteeother operations

Adapter

Client<<use>>

1

Iterator

Enumeration

• We’ll discuss two more variants: Proxy and Facade.• Not too complicated

Page 22: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

22

Adding a reporting function to parking machines

ParkingMachinelocation()count()hours()

Report+ printReport ()

printReport() { for (Machine m : machines) { print m.location() print m.count() print m.hours() }}

machines

Does not work if the parking machines objects exist on physically different computers.

We need a networking solution, but want a nice way to fit that into our design.

*

Page 23: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

23

Proxy pattern

Report+ printReport ()

ParkingMachinelocation()count()hours()

<<interface>>ParkingMachineInterfacelocation()count()hours()

ParkingMachine

ParkingMachineProxy

client sideremote side

The proxy pass requests to the actual subject; implying it implements this passing mechanism, e.g. over Internet

Create a “stand-in” for another object; useful when the real object is remote, or expensive to create, or require securing.

subject

real subject

*

Page 24: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

24

Home cinema

Page 25: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

25

Ok.. let’s watch a film now

• Complicated...• How about when we are

done watching film.• How about listening to

music? etc• What if we upgrade the

system?

Page 26: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

26

Facade pattern

To provide a simplified interface.

HomeCinemaFacedewatchFilm()listenCD()

Client<<use>>

So... can you say when it is more appropriate to use one of these over the other ?• Adapter• Proxy• Facade• Decorator

Page 27: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

27

Candy machine…

no coin

has coin

sold

empty

inse

rt co

in

turn crank

/ [counter is updated]

[not empty]

[empty]

CandyMachine- state+ insertCoin(c)+ turnCrank()+ getCandy()

get candy

insert coin

turn crank

get candy[1eur]

[else

] / [

coin

is e

ject

ed]

Page 28: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

28

Mapping this to implementation

class CandyMachine { static final NOCOIN = 0 static final HASCOIN = 1 static final SOLD = 2 static final EMPTY = 3

private state private n

CandyMachine() { this.n = 200 state = NOCOIN }}

insertcoin(c) { if (state == NOCOIN) { if (c is 1 euro) state = HASCOIN else eject c } else eject c}

getcandy() { if (state == SOLD) { n-- if (n==0) state = EMPTY else state = NOCOIN } else skip}

Page 29: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

29

The company wants to add usr messaging

insertcoin(c) { if (state == NOCOIN) { if (c is 1 euro) state = HASCOIN else { print “Not 1 euro” eject c } } else if (state == HASCOIN || state == SOLD) { print “You have inserted a coin” eject c } else if (state == EMPTY) { print “the machine is empty” eject c }}

getcandy() { if (state == SOLD) { if (n==0) state = EMPTY else state = NOCOIN } else if (state == NOCOIN) print “You have not inserted a coin” else if (state == HASCOIN) print “You =have not turned the crank” …}

Page 30: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

30

The company wants to add prize ball!

no coin

has coin

sold

empty

inse

rt co

in

turn crank

/ [counter is updated]

[not empty]

[empty]

get candy

[1eur]

[else

] / [

coin

is e

ject

ed]

bonus

get candy

turn crank[n>1]

/ [counter is updated]

Implementationblows!

turn crank

/ [counter is updated]

Page 31: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

31

Encapsulating state

CMstateinsertCoin(c)turnCrank()getcandy()

NoCoinSt

HasCoinSt

SoldSt

EmptySt

candyMachine- n : int+ insertCoin(c)+ turnCrank()+ getcandy()

(current) state

1

owner

0..1

candyMachine() { n = 200 state = new NoCoin(this)}

NoCoinSt(machine) { owner = machine}

insertCoin(c) { state.insertCoin(c) }turnCrank() { state.turnCrank() }getcandy() { state.getcandy() }

Simple candy Machine !

(abstract class)

Page 32: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

32

Implementing the states

CMstateinsertCoin(c)turnCrank()getcandy()

NoCoinSt

HasCoinStcandyMachine 1

owner

0..1 …

insertCoin(c) { if (c is 1 euro) owner.state = new HasCoinSt(owner) else { print “not 1 euro coin” ; eject c }}

insertCoin(c) { print “you have inserted a coin” ; eject c }}

getcandy() { print “you have not inserted a coin”}

getcandy() { print “you must first turn the crank” }}

insertcoin(c) { if (state == NOCOIN) { if (c is 1 euro) state = HASCOIN else { print “Not 1 euro” eject c } } else if (state == HASCOIN || state == SOLD) { print “You have inserted a coin” eject c } else if (state == EMPTY) { print “the machine is empty” eject c }}

getcandy() { if (state == SOLD) { if (n==0) state = EMPTY else state = NOCOIN } else if (state == NOCOIN) print “You have not inserted a coin” else if (state == HASCOIN) print “You =have not turned the crank” …}

Page 33: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

33

What is the point of this?

CMstateinsertCoin(c)turnCrank()getcandy()

NoCoinSt

HasCoinSt

SoldSt

EmptySt

candyMachine- n : int+ insertCoin(c)+ turnCrank()+ getcandy()

(current) state

1

owner

0..1

BonusSt

What need to be done ?

• Obviously implement BonusSt this implements all arrows leaving Bonus• We still have to code incoming arrows turnCrank of HasCoinSt

The changes in the existing code is minimized!

Page 34: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

34

State pattern

Extensible implementation of state-machine.(dev. from FF)

Stateoperation1(..)operation2(..)

Concrete State 1

Concrete State 2

StMachineoperation1(..)operation2(..)

(current) state

1

owner

0..1…

<<interface>>Statehandle(..)

Concrete State 1

Concrete State 2

Contextrequest(..)

…request(..) { state.handle(..) }

FF:

Page 35: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

35

Back to our restaurants…

DinnerMenu

PancakeHouseMenuMenu

(deviate a bit from FF)

CafeMenuMenuItem

*

Page 36: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

36

What if we plan to add submenus in the future?all menus

: DinnerMenu : PancakeMenu : CafeMenu

MenuItems

: Dessert Menu

We need a tree structure.And a convenient and extensible way to implement computations that traverse the tree, like:• Counting the menu items• Get the cheapest menu item• Checking if a menu item is present

Page 37: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

37

Composite pattern

Componentoperation(..)add(component)remove(component) getChild(k)

Compositeoperation(..)add(component)remove(component) getChild(k) // or getChildren() .. or ret. iterator

Leafoperation(..)

* components

:Composite

:Composite:Leaf :Leaf

:Leaf :Leaf

:Composite

:Leaf :Leaf

(FF’s formulation of the pattern)

operation e.g. get all leaves

Page 38: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

38

DiscussionComponentoperation(..)add(component)remove(component) getChild(k)

Compositeoperation(..)add(component)remove(component) getChild(k)

Leafoperation(..)

* components

• Forcing some operations on Leaf• Circularity• getChild does not seem very useful

children () : List<Component>(alternatively, return an iterator)

Page 39: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

39

Implementation

<<interface>>MenuComponentoperation(..)

Menuadd(component)remove(component)

MenuItemnamedescprice

* components

class Menu { components = new LinkedList<...>()

add(c) { components.add(c) } remove(c) { components.remove(c) }

}

Page 40: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

40

Operation : counting menu items

<<interface>>MenuComponentcountMenuItems()

Menuadd(component)remove(component)

MenuItemnamedescprice

* components class Menu { components …

countMenuItems() { n = 0 for (MenuComponent m : components) n += m.countMenuItems()) return n }}

class MenuItem { countMenuItems() { return 1 }}

Page 41: Design Pattern 2 [FF 6 – 11]. Remember Starbuzz Coffee? 2 Coffee instruction 1.Boil water 2.Brew coffee in boiling water 3.Pour the mix in cup 4.Add sugar

41

Operation : getting the cheapest menu item

<<interface>>MenuComponentcountMenuItems()getCheapest()

Menuadd(component)remove(component)

MenuItemnamedescprice

* components class Menu { components …

getCheapest() { p = MAXINT c = null for (MenuComponent m : components) { d = m.getCheapest() if (d != null && d.price < p) { c = d ; p = d.price } } return c }}

class MenuItem { getCheapest() { return this }}