Præsentation er lastning. Vent venligst

Præsentation er lastning. Vent venligst

Designmønstre Composite, Template Method, Strategy og State

Lignende præsentationer


Præsentationer af emnet: "Designmønstre Composite, Template Method, Strategy og State"— Præsentationens transcript:

1 Designmønstre Composite, Template Method, Strategy og State
Michael E. Caspersen Datalogisk Institut Aarhus Universitet

2 Dagens emner Composite Template Method Strategy State
Definition á la GoF Eksempler Template Method Strategy State Programmeringsteknologi, F11 Designmønstre

3 Composite

4 Opgave 3.A: Model for PowerPoint
Der skal laves et system á la PowerPoint der kan lave dias som indeholder både tekst og grafik. Systemet skal være effektivt, brugervenligt og med mulighed for senere udvidelse af funktionaliteten. Systemet skal være et WYSIWYG-system hvor brugeren løbende skal kunne se hvordan den færdige præsentation kommer til at se ud. Tilsvarende skal det være muligt at ændre layout og indhold af præsentationens dias på en simpel måde og gennem direkte manipulation af elementerne i hvert dias. For eksempel skal man kunne lave en figur på et dias ved at lægge et grafisk billede og en billedtekst ind, og få tegnet en kasse rundt om. Det skal være muligt at skifte størrelse på figuren, og kassens størrelse skal da følge figurens størrelse. Det skal være muligt at flytte figuren både sammen med og uafhængigt af teksten (dog ikke samtidig :-). Det skal være muligt at gruppere elementer i et dias således at disse kan manipuleres under et (for eksempel ved flytning, kopiering, animering, etc.). Lav en klassemodel for centrale dele af den her skitserede applikation. Programmeringsteknologi, F11 Designmønstre

5 En løsning (begrebsmodel)
void move(int dx, int dy) Item copy() void scaleHorizontal(int sf) void scaleVertical(int sf) void scaleLockedRatio(int sf) void rotate(int angle) order(int level) ... * Presentation Dias * * Item Text Picture Graphics Group Programmeringsteknologi, F11 Designmønstre

6 Udtryk (projektopgave nr. 2)
1 2 Exp UnaryExp Num Identifier BinaryExp Programmeringsteknologi, F11 Designmønstre

7 Composite á la (1) Intent Motivation
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. Motivation Programmeringsteknologi, F11 Designmønstre

8 Composite á la (2) Structure Object structure
Programmeringsteknologi, F11 Designmønstre

9 Composite á la (3) Component (Graphic)
declares the interface for objects in the composition implements default behavior for the interface common to all classes, as appropriate declares an interface for accessing and managing its child components (optional) defines an interface for accessing a component's parent in the recursive structure, and implements it if that's appropriate Leaf (Rectangle, Line, Text, etc.) represents leaf objects in the composition; a leaf has no children defines behavior for primitive objects in the composition Composite (Picture) defines behavior for components having children stores child components implements child-related operations in the Component interface Client manipulates objects in the composition through the Component interface Programmeringsteknologi, F11 Designmønstre

10 Composite á la (4) Consequences of the Composite Pattern
Defines class hierarchies consisting of primitive objects and composite objects. Primitive objects can be composed into more complex objects, which in turn can be composed, and so on recursively. Wherever client code expects a primitive object, it can also take a composite object. Makes the client simple. Clients can treat composite structures and individual objects uniformly. Clients normally don't know (and shouldn't care) whether they're dealing with a leaf or a composite component. This simplifies client code, because it avoids having to write tag-and-case-statement-style functions over the classes that define the composition. Makes it easier to add new kinds of components. Newly defined Composite or Leaf subclasses work automatically with existing structures and client code. Clients don't have to be changed for new Component classes. Can make your design overly general. The disadvantage of making it easy to add new components is that it makes it harder to restrict the components of a composite. Sometimes you want a composite to have only certain components. With Composite, you can't rely on the type system to enforce those constraints for you. You'll have to use run-time checks instead. Programmeringsteknologi, F11 Designmønstre

11 GUI-komponenter (Java)
En GUI består af en række grafiske komponenter knapper, lister, tekstfelter Disse fremstår i et visuelt layout i en grafisk container en applet, en dialogboks, et vindue, eller et selvstændigt vinduesbaseret program (frame) Betegnelsen Container er velvalgt indeholder polymorfe objekter nøjagtig som Collections Programmeringsteknologi, F11 Designmønstre

12 java.awt.Component Component, ej Container Container
Programmeringsteknologi, F11 Designmønstre

13 Kompositionshierarkier
Enhver GUI i Java er et kompositionshierarki Et antal komponenter i en container: anApplet aCanvas aPanel aButton aButton aChoice Container Component, ej Container Programmeringsteknologi, F11 Designmønstre

14 Template Method

15 Generalisering af kaffe- og tebrygning
Kaffe-opskrift Kog vand Bryg kaffe med kogende vand Hæld kaffe i kop Kom mælk og sukker i Te-opskrift Kog vand steep Lad te trække i kogende vand Hæld te i kop Kom citron i Abstraktion: Generalisering Opskrift for brygning af varme drikke Kog vand Udtræk smagsstof i kogende vand Hæld drik i kop Kom tilsætningsstoffer i Programmeringsteknologi, F11 Designmønstre

16 Java-brygning af varme drikke
abstract class CaffeineBeverage { final void prepareRecipe() { boilWater(); brew(); pourInCup(); addCondiments(); } abstract void brew(); abstract void addCondiments(); class Tea extends CaffeineBeverage { void brew() { ... } void addCondiments() { ... } } class Coffee extends CaffeineBeverage { abstract void brew() { ... } abstract void addCondiments() { ... } } Programmeringsteknologi, F11 Designmønstre

17 Template Method á la (1) Intent Motivation
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. Motivation Invariant Variant Programmeringsteknologi, F11 Designmønstre

18 Template Method á la (2) Structure Participants
AbstractClass (Application) defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects ConcreteClass (MyApplication) implements the primitive operations to carry out subclass-specific steps of the algorithm . Programmeringsteknologi, F11 Designmønstre

19 Template Method á la (3) Consequences
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries, because they are the means for factoring out common behavior in library classes. Template methods lead to an inverted control structure that's sometimes referred to as "the Hollywood principle”, that is, "Don't call us, we'll call you". This refers to how a parent class calls the operations of a subclass and not the other way around. Programmeringsteknologi, F11 Designmønstre

20 Eksempel: Grafik abstract class TegneObjekt { private int x, y;
public final void move(int dx, int dy) { hide(); x += dx; y += dy; show(); } public abstract void show(); public abstract void hide(); Programmeringsteknologi, F11 Designmønstre

21 Eksempel: Undtagelseshåndtering
class MyStack extends Stack { private void handleUnderflow() { ”fejlhåndtering som passer til min applikation” } class Stack { ... public final void pop(Object e) { if (isEmpty()) handleUnderflow(); else ”normal situation” } private void handleUnderflow() {} Hook method: En metode erklæret i en abstrakt klasse med default implementation (evt. tom). Open-Closed Principle: Moduler skal være åbne for udvidelser, men lukkede for modifikation. — If it ain’t broke, don’t fix it! Programmeringsteknologi, F11 Designmønstre

22 Strategy

23 Strategy á la (1) Intent Structure
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. Structure Programmeringsteknologi, F11 Designmønstre

24 Strategy á la (2) Participants Strategy
Declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy Implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects. ConcreteStrategy implements the algorithm using the Strategy interface. Context is configured with a ConcreteStrategy object maintains a reference to a Strategy object may define an interface that lets Strategy access its data Programmeringsteknologi, F11 Designmønstre

25 Eksempel: GUI i Java Mange tidligere tilgange til layout har været direkte koordinatbaserede: Denne tilgang er “uheldig”: det er meget svært at kode en GUI tekstuelt x y changeButton.setSize(20,50); changeButton.setPosition(80, 60); Programmeringsteknologi, F11 Designmønstre

26 Alternativ til koordinatbasering
Første bud på en løsning: GUI-Builders interaktive værktøjer hvor man kan editere sin GUI grafisk genererer derefter koordinatbaseret kildetekst Men det er ikke godt nok Java skal være platformuafhængigt men størrelsen af knapper, skrifttyper m.m. varierer fra platform til platform... I stedet for absolut placering specificeres den relative placering af komponenterne i en GUI LayoutManagers har ansvaret for placering af komponenter i containere Programmeringsteknologi, F11 Designmønstre

27 LayoutManager Layoutet af componenterne i en container bestemmes af containerens LayoutManager Ikke den absolutte, men den relative placering af komponenterne specificeres Positionen og størrelsen af komponenterne vil automatisk blive justeret når vinduets størrelse ændres Programmeringsteknologi, F11 Designmønstre

28 FlowLayout width = 400 height = 50 width = 100 height = 200
Programmeringsteknologi, F11 Designmønstre

29 FlowLayout (2) public class Flow extends Applet { public Flow () {
// FlowLayout is default, but ... setLayout(new FlowLayout()); add(new Button("Java")); add(new Button("C++")); add(new Button("Perl")); add(new Button("Ada")); add(new Button("Smalltalk")); add(new Button("Eiffel")); } Programmeringsteknologi, F11 Designmønstre

30 BorderLayout Programmeringsteknologi, F11 Designmønstre

31 BorderLayout (2) import java.awt.*; import java.applet.Applet;
public class Border extends Applet { public Border () { setLayout(new BorderLayout()); add("South", new Button("South")); add("North", new Button("North")); add("East", new Button("East")); add("West", new Button("West")); add("Center", new Button("Center")); } Programmeringsteknologi, F11 Designmønstre

32 GridLayout row = 1 col = 0 row = 3 row = 0 col = 2 col = 1
Programmeringsteknologi, F11 Designmønstre

33 GridLayout (2) public class Grid extends Applet {
public void init () { int row = 0, col = 0; // row = ...; // col = ...; setLayout(new GridLayout(row, col)); add(new Button("Java")); add(new Button("C++")); add(new Button("Perl")); add(new Button("Ada")); add(new Button("Smalltalk")); add(new Button("Eiffel")); } Programmeringsteknologi, F11 Designmønstre

34 Nestede paneler Programmeringsteknologi, F11 Designmønstre

35 Nestede paneler (2) public class NestedPanels extends Applet {
public NestedPanels () { Panel center = new Panel(); ... Panel south = new Panel(); setLayout(new BorderLayout()); add("North", new Button("North")); add("East", new Button("East")); add("West", new Button("West")); add("South", south); add("Center", center); } protected Label messageBar; protected Choice choice; Programmeringsteknologi, F11 Designmønstre

36 Nestede paneler (3) Panel center = new Panel();
center.setLayout(new BorderLayout()); center.add("South", new Button(”Syd")); center.add("North", new Button(”Nord")); center.add("East", new Button(”Øst")); center.add("West", new Button(”Vest")); center.add("Center", new Button(”Center")); Panel south = new Panel(); south.setLayout(new FlowLayout()); south.add(new Button("Help")); choice = new Choice(); choice.addItem("one"); choice.addItem("two"); choice.addItem("three"); choice.addItem("four"); choice.addItem("five"); south.add(choice); messageBar = new Label("This is a message bar."); south.add(messageBar); Programmeringsteknologi, F11 Designmønstre

37 Andre LayoutManagere CardLayout GridBagLayout Din helt egen manager
hver komponent fylder det hele fungerer som kort ovenpå hinanden GridBagLayout yderst fleksibel, men kompliceret Din helt egen manager ved at udvide LayoutManager, kan man definere sin egen LayoutManager ColumnLayout, udlægger komponenter i deres standardstørrelse som FlowLayout, men fra oven og nedefter (se f.eks. “Java Examples in a Nutshell”) Programmeringsteknologi, F11 Designmønstre

38 LayoutManager, hierarkiet
Strategy 1 setLayout (LayoutManager lm) Programmeringsteknologi, F11 Designmønstre

39 Søgeskabelon Søgedomæne: S Kandidatmængde: K kandidatelement : e
kandidatelement : e Målelement : m I et søgedomæne, S, søger vi efter et målelement, m. På et givet tidspunkt under søgningen har vi afsøgt en del af søgedomænet; den resterende del kalder vi kandidatmængden, K. Et skridt i søgningen består i at vælge et (tilfældigt) kandidatelement, e, fra kandidatmængden og sammenligne dette med målelementet m. Enten har vi fundet det vi søger, eller også afskærer vi en del af kandidatmængden. Søgningen slutter når vi har fundet det vi søger eller når kandidatmængden er tom. Programmeringsteknologi, F11 Designmønstre

40 Søgeskabelon, algoritmisk
initialiser K ; found = false ; while ( !found && K  Ø ) { udvælg e fra K ; if ( e == m ) found = true ; else split K ; } Programmeringsteknologi, F11 Designmønstre

41 Konkretisering af skabelonen
initialiser K : K  Ø : udvælg e fra K : split K : s[0..s.size()) i = 0; i != s.size() e = s.elementAt(i); i++; s: e i Programmeringsteknologi, F11 Designmønstre

42 Lineær søgning public static boolean search(int m, Sequence s) {
// post: returnerer om m findes i s boolean found; // resultat-variabel i = 0; found = false; while ( !found && i != s.size() ) { int e = s.elementAt(i); if ( e == m ) found = true; else i++; } return found; Programmeringsteknologi, F11 Designmønstre

43 Binær søgning S : initialiser K : K  Ø : udvælg e fra K : split K :
mi h S : initialiser K : K  Ø : udvælg e fra K : split K : s[0..s.size()) l = 0 ; h = s.size(); l < h mi = (l+h)/2; e = s.elementAt(mi) if ( e < m ) l = mi+1; else // e > m h = mi; Programmeringsteknologi, F11 Designmønstre

44 Bineær søgning (Java) public static boolean search(int m, Sequence s) { // pre: s er sorteret (  ) // post: returnerer om m findes i s boolean found; // resultat-variabel l = 0; h = s.size(); found = false; while ( !found && l<h ) { int mi = (l+h)/2; int e = s.elementAt(mi); if ( e == m ) found = true; else if ( e < m ) l = mi+1; else // e > m h = mi; } return found; Programmeringsteknologi, F11 Designmønstre

45 Søgeskabelon realiseret med Strategy
<<interface>> Searchable Searcher void init() boolean isEmpty() select() split(Object e) search() SomeList SomeTree void init() boolean isEmpty() select() split(Object e) void init() boolean isEmpty() select() split(Object e) Programmeringsteknologi, F11 Designmønstre

46 Genericity vha. interfaces
interface Searchable<T> { public void init(); public boolean isEmpty(); public T select(); public void split(T e); } public static <T> boolean search(Searchable s, T m) { // assuming element type to implement equals s.init(); boolean found = false; while ( !found && !s.isEmpty() ) { T e = s.select(); if (e.equals(m) ) found = true; else s.split(e); } return found; Programmeringsteknologi, F11 Designmønstre

47 Template Method versus Strategy
Begge mønstre er eksempler på udfaktorisering a*b + a*c = a*(b+c) Begge mønstre separerer en generisk algoritme fra specifikke kontekster Template Method Den generiske algoritme faktoriseres til en abstrakt superklasse Specifik kontekst konkretiseres i subklasser Strategy Den generiske algoritme faktoriseres til en konkret klasse Specifik kontekst abstraheres til et interface Generisk algoritme delegerer til specifik kontekst via interface Programmeringsteknologi, F11 Designmønstre

48 State

49 State og Strategy Det er de færreste der ved det, men …
Strategy og State er tvillinger der blev separeret ved fødslen. Strategy har skabt sig en succesfuld forretning omkring udskiftbare algoritmer. State gik en anden vej og hjælper objekter med at kontrollere deres opførsel ved at ændre deres interne tilstand. Cryptomathic, F05 Designmønstre

50 Mighty Gumball Inc. inserts quarter No Quarter Has Quarter
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) Cryptomathic, F05 Designmønstre

51 FSM State (tilstand) Event (hændelse) No Quarter Has Quarter
Gumball Sold Out of gumballs Event (hændelse) inserts quarter ejects quarter turns crank dispense gumball Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) Cryptomathic, F05 Designmønstre

52 Modellering af FSM i software
Nestede switch-sætninger (softwaretabel) switch state ... switch event switch event ... switch state Datastruktur 2-dimensionalt array Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) Events States Handling Ny tilstand Cryptomathic, F05 Designmønstre

53 Tilstande og events som tal
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) final static int INSERT_QUARTER = 0; final static int EJECT_QUARTER = 1; final static int TURN_CRANK = 2; final static int DISPENSE_GUMBALL = 3; final static int NO_QUARTER = 0; final static int HAS_QUARTER = 1; final static int SOLD = 2; final static int SOLD_OUT = 3; int event = INSERT_QUARTER; int state = NO_QUARTER; Cryptomathic, F05 Designmønstre

54 Eventhandler public void eventHandler(int event) { switch event {
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) public void eventHandler(int event) { switch event { INSERT_QUARTER: insertQuarter(); break; EJECT_QUARTER: ejectQuarter(); break; TURN_CRANK: turnCrank(); break; DISPENSE_GUMBALL: dispenseGumball(); break; } Cryptomathic, F05 Designmønstre

55 insertQuarter() // eventhandler for INSERT_QUARTER
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) // eventhandler for INSERT_QUARTER public void insertQuarter() { switch state NO_QUARTER: state = HAS_QUARTER; println(”You inserted a quarter”); break; HAS_QUARTER: error(”You can’t insert another quarter, turn the crank”); SOLD: error(”Please wait, we are already giving you a gumball”); SOLD_OUT: error(”You can’t buy a gumball, the machine is sold out”); } public void ejectQuarter() { ... } public void turnCrank() { ... ; dispenseGumball(); } public void dispenseGumball() { ... } Cryptomathic, F05 Designmønstre

56 Eller omvendt... Statehandler
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) public void stateHandler(int event) { switch state { NO_QUARTER: noQuarter(); break; HAS_QUARTER: hasQuarter(); break; SOLD: sold(); break; SOLD_OUT: soldOut(); break; } Cryptomathic, F05 Designmønstre

57 noQuarter() // statehandler for NO_QUARTER public void noQuarter() {
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) // statehandler for NO_QUARTER public void noQuarter() { switch event INSERT_QUARTER: state = HAS_QUARTER; println(”You inserted a quarter”); break; EJECT_QUARTER: error(”Sorry, there is no quarter to eject”); TURN_CRANK: error(”Please insert a quarter”); DISPENSE_GUMBALL: debug(”illegal event in state NO_QUARTER”); } public void hasQuarter() { ... } public void sold() { ... } public void soldOut() { ... } Cryptomathic, F05 Designmønstre

58 Nye krav (det måtte jo komme...)
Vi gør tyggegummikøb til et spil og forøger vores salg betragteligt!!! En sticker på hver maskine skal lokke kunderne til vores maskiner. Og med Java inden i bliver det en leg... Be a Winner! One in Ten get a FREE GUMBALL Cryptomathic, F05 Designmønstre

59 Øvelse Be a Winner! One in Ten get a FREE GUMBALL Lav en tilstandsmaskine til en tyggegummimaskine der kan klare ”One in a Ten” kravet. 10% af gangene skal der dispenseres to kugler i stedet for en. Cryptomathic, F05 Designmønstre

60 Løsning inserts quarter No Quarter Has Quarter ejects quarter
dispense 2 gumballs (#gumballs > 0) turns crank, winner Winner Out of Gumballs dispense gumball (#gumballs > 0) turns crank, no winner dispense gumball (#gumballs = 0) Gumball Sold dispense 2 gumballs (#gumballs = 0) Cryptomathic, F05 Designmønstre

61 Og så ændringerne i koden... (suk!)
final static int NO_QUARTER = 0; final static int HAS_QUARTER = 1; final static int SOLD = 2; final static int SOLD_OUT = 3; final static int WINNER = 4; // eventhandler for INSERT_QUARTER public void insertQuarter() { switch state NO_QUARTER: state = HAS_QUARTER; println(”You inserted a quarter”); break; HAS_QUARTER: error(”You can’t insert another quarter, turn the crank”); SOLD: error(”Please wait, we are already giving you a gumball”); SOLD_OUT: error(”You can’t buy a gumball, the machine is sold out”); WINNER: } public void ejectQuarter() { ... WINNER: ... } public void turnCrank() { ... WINNER: ... ; dispenseGumball(); } public void dispenseGumball() { ... WINNER: ... } Cryptomathic, F05 Designmønstre

62 Karakteristik af softwaredesignet, sæt kryds
X Koden overholder ikke open/closed principper Koden ville gøre en FORTRAN-programmør stolt Designet er ikke specielt objekt-orienteret Tilstandsovergange er ikke eksplicitte; de er begravet dybt inde i et virvar af switch-sætninger Vi har ikke indkapslet det der varierer Tilføjelser vil højst sandsynligt introducere fejl i gammel kode X X X X X Cryptomathic, F05 Designmønstre

63 Nyt design Først definerer vi et State interface
indeholder en metode for hver hændelse Dernæst implementerer vi en State klasse for hver konkret tilstand i maskinen disse klasser har ansvar for maskinens opførsel når den er i den pågældende tilstand Til sidst kan vi få ryddet op i alle switch-sætningerne i stedet delegeres til state-objekterne der gør arbejdet for os (dynamisk binding erstatter conditionals) Cryptomathic, F05 Designmønstre

64 <<interface>>
Klassedesign <<interface>> State insertQuarter() ejectQuarter() turnCrank() dispenseGumball() SoldState insertQuarter() ejectQuarter() turnCrank() dispenseGumball() SoldOutState NoQuarterState HasQuarterState WinnerState insertQuarter() ejectQuarter() turnCrank() dispenseGumball() Cryptomathic, F05 Designmønstre

65 Specifikation af opførsel...
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) NoQuarterState insertQuarter() ejectQuarter() turnCrank() dispenseGumball() Skift til HasQuarterState Giv besked om at der ikke er indbetalt en krone SoldState insertQuarter() ejectQuarter() turnCrank() dispenseGumball() Giv besked om at vente Aflever en kugle. Check om der er flere kugler; hvis der er skiftes til NoQuarterState og ellers skiftes til SoldOutState Cryptomathic, F05 Designmønstre

66 <<interface>>
Klassestruktur Gumball Machine <<interface>> State insertQuarter() ejectQuarter() turnCrank() dispenseGumball() ... 1 * insertQuarter() ejectQuarter() turnCrank() dispenseGumball() 1 SoldState insertQuarter() ejectQuarter() turnCrank() dispenseGumball() SoldOutState NoQuarterState HasQuarterState WinnerState insertQuarter() ejectQuarter() turnCrank() dispenseGumball() Cryptomathic, F05 Designmønstre

67 Eventhandler . Delegering til State-objekt
public class GumballMachine { State soldOutState; State noQuarterState; State hasQuarterState; State soldState; public GumballMachine(int numberGumballs) { soldOutState = new SoldOutState(this); ... this.count = numberGumballs; if (numberGumballs > 0) { state = noQuarterState; } else { state = soldOutState; } } public void insertQuarter() { state.insertQuarter(); } public void ejectQuarter() { state.ejectQuarter(); } public void turnCrank() { state.turnCrank(); state.dispense(); } . Delegering til State-objekt Cryptomathic, F05 Designmønstre

68 Implementation af NoQuarterState
public class NoQuarterState implements State { GumballMachine gumballMachine; public NoQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { System.out.println("You inserted a quarter"); gumballMachine.setState(gumballMachine.getHasQuarterState()); public void ejectQuarter() { System.out.println("You haven't inserted a quarter"); public void turnCrank() { System.out.println("You turned, but there's no quarter"); public void dispense() { System.out.println("You need to pay first"); public String toString() { return "waiting for quarter"; Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) Cryptomathic, F05 Designmønstre

69 Implementation af SoldState
public class SoldState implements State { GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { System.out.println("Please wait, we're already giving you a gumball"); public void ejectQuarter() { System.out.println("Sorry, you already turned the crank"); public void turnCrank() { System.out.println("Turning twice doesn't get you another gumball!"); public void dispense() { gumballMachine.releaseBall(); if (gumballMachine.getCount() > 0) { gumballMachine.setState(gumballMachine.getNoQuarterState()); } else { System.out.println("Oops, out of gumballs!"); gumballMachine.setState(gumballMachine.getSoldOutState()); Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank dispense gumball (#gumballs > 0) (#gumballs = 0) Cryptomathic, F05 Designmønstre

70 Øvelse Implementer klasserne HasQuarterState og WinnerState.
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank, no winner dispense gumball (#gumballs > 0) (#gumballs = 0) Winner winner dispense 2 gumballs Cryptomathic, F05 Designmønstre

71 Løsning (Winner) public class GumballMachine { State soldOutState;
State noQuarterState; State hasQuarterState; State soldState; State winnerState public GumballMachine(int numberGumballs) { soldOutState = new SoldOutState(this); ... winnerState = new WinnerState(this); this.count = numberGumballs; if (numberGumballs > 0) { state = noQuarterState; } else { state = soldOutState; } } public void insertQuarter() { state.insertQuarter(); } public void ejectQuarter() { state.ejectQuarter(); } public void turnCrank() { state.turnCrank(); state.dispense(); } Cryptomathic, F05 Designmønstre

72 WinnerState Samme som SoldState .
public class WinnerState implements State { GumballMachine gumballMachine; public WinnerState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { ... } public void ejectQuarter() { ... } public void turnCrank() { ... } // pre: gumballMachine.getCount() > 1 public void dispense() { System.out.println("YOU'RE A WINNER! You get two gumballs"); gumballMachine.releaseBall(); if (gumballMachine.getCount() > 0) { gumballMachine.setState(gumballMachine.getNoQuarterState()); } else { System.out.println("Oops, out of gumballs!"); gumballMachine.setState(gumballMachine.getSoldOutState()); Samme som SoldState . Cryptomathic, F05 Designmønstre

73 Implementation af HasQuarterState
public class HasQuarterState implements State { Random randomWinner = new Random(System.currentTimeMillis()); GumballMachine gumballMachine; public void turnCrank() { System.out.println("You turned..."); int winner = randomWinner.nextInt(10); if ((winner == 0) && (gumballMachine.getCount() > 1)) { gumballMachine.setState(gumballMachine.getWinnerState()); } else { gumballMachine.setState(gumballMachine.getSoldState()); } ... Se tilstandsmaskinen næste side... Cryptomathic, F05 Designmønstre

74 Tilstandsmaskinen, igen...
Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank, no winner dispense gumball (#gumballs > 0) (#gumballs = 0) Winner winner dispense 2 gumballs Cryptomathic, F05 Designmønstre

75 Diskussion WinnerState har meget til fælles med SoldState; hvad kan man gøre ved det? Out of Gumballs Gumball Sold No Quarter Has Quarter inserts quarter ejects quarter turns crank, no winner dispense gumball (#gumballs > 0) (#gumballs = 0) Winner winner dispense 2 gumballs Cryptomathic, F05 Designmønstre

76 Testing... It rocks!!! Be a Winner! One in Ten get a FREE GUMBALL
public class GumballMachineTestDrive { public static void main(String[] args) { GumballMachine gumballMachine = new GumballMachine(5); System.out.println(gumballMachine); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); } It rocks!!! Be a Winner! One in Ten get a FREE GUMBALL Cryptomathic, F05 Designmønstre

77 State á la (1) Intent Motivation
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. Motivation Invariant Variant Cryptomathic, F05 Designmønstre

78 State á la (2) Structure Participants
Context (GumballMachine, TCPConnection) defines the interface of interest to clients. maintains an instance of a ConcreteState subclass that defines the current state. State ((Gumball) State, TCPState) defines an interface for encapsulating the behavior associated with a particular state of the Context. ConcreteState subclasses (NoQuarter, HasQuarter, ..., TCPEstablished, TCPListen, TCPClosed) each subclass implements a behavior associated with a state of the Context. Cryptomathic, F05 Designmønstre

79 State á la (3) Consequences
It localizes state-specific behavior and partitions behavior for different states. The State pattern puts all behavior associated with a particular state into one object. Because all state-specific code lives in a State subclass, new states and transitions can be added easily by defining new subclasses. It makes state transitions explicit. When an object defines its current state solely in terms of internal data values, its state transitions have no explicit representation; they only show up as assignments to some variables. Introducing separate objects for different states makes the transitions more explicit. Also, State objects can protect the Context from inconsistent internal states, because state transitions are atomic from the Context's perspective—they happen by rebinding one variable. Cryptomathic, F05 Designmønstre

80 State versus Strategy Hvad er forskellen? Intention!
State: Allow an object to alter its behavior when its internal state changes. The object will appear to change its class Strategy: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. Cryptomathic, F05 Designmønstre

81 Composite, Template Method, Strategy og State
Programmeringsteknologi, F11 Designmønstre


Download ppt "Designmønstre Composite, Template Method, Strategy og State"

Lignende præsentationer


Annoncer fra Google