© 2006 Pearson EducationDesign Patterns1 of 20 A Final Example: A Traffic Light Let’s model a traffic light! – here’s the spec: Have a column of two circles representing lights. When the program starts, the top light should be red (on) and the bottom one black (off). Beneath the lights should be a button. When this button is pressed, the lights should change their state so that the top one is black (off) and the bottom one is green (on). The next time the button is pressed, the red light becomes active. Each time the button is pressed, the lights will toggle between red and green. Note a subtle difference between this example and the ShapeColorChanger : –for the ShapeColorChanger, the state of the color changer was remembered by the column of radio buttons –this traffic light example will have no such radio button column –a new design pattern (the “State” pattern) will have to be used to keep track of the state
© 2006 Pearson EducationDesign Patterns2 of 20 Analyzing the Specification We’ll start by underlining nouns: Have a column of two circles representing lights. When the program starts, the top light should be red (on) and the bottom one black (off). Beneath the lights should be a button. When this button is pressed, the lights should change their state so that the top one is black (off) and the bottom one is green (on). The next time the button is pressed, the red light becomes active. Each time the button is pressed, the lights will toggle between red and green. Some we don’t have to deal with because they have been provided –JPanels, gfx.ColorEllipse, and JButton Let’s focus on the one new noun: –state
© 2006 Pearson EducationDesign Patterns3 of 20 Class Diagram Most of design is simple –Frame contains TrafficLight –TrafficLight contains Light s and button that changes Light s (and probably a QuitButton too) –also contains something that models how it responds to button being pressed What can we do to model the state of the light? = “contains multiple instances of” Frame TrafficLight ???LightLightChangeButton
© 2006 Pearson EducationDesign Patterns4 of 20 States and State Diagrams What do we need? –something that encapsulates TrafficLight ’s response to user clicking button –make subclasses that model possible responses –but how do we know when to add and remove each response? State: n. 1. a mode or condition of being –State Diagrams represent an exhaustive (i.e., complete) enumeration of an object’s possible states and how to move between them –graphical notation that helps you understand dynamic behavior of object State Diagrams are composed of states and transitions among them –recall that object’s state is value of its properties at a given moment in time –object’s methods change those values, thus cause object to make a transition, i.e., “move” between states –think of method as a stimulus, transition to next state as response Let’s see an example!
© 2006 Pearson EducationDesign Patterns5 of 20 Reading a State Diagram State Diagrams are programming language independent –graphical notation like class and instance diagrams but have very different semantic meaning –states are represented by a circle start states are denoted by a “>” next to a circle final states are denoted by a double circle –transitions are represented by an arc linking two circles transitions are marked by arrows because they are directed transitions describe a sequence of method calls egg larvapupa butt erfly changeSeason() hatch() suckHoney() eatLeaves()
© 2006 Pearson EducationDesign Patterns6 of 20 State Pattern Defines way of changing object’s behavior at run-time according to state of its properties Delegate response to a separate object that represents a state in state diagram –state knows how to handle message –just change state behavior Advantages: –makes primary class more flexible can change primary class’ behavior at run-time Disadvantages: –must design a new class hierarchy to represent states –too much delegation can be confusing
© 2006 Pearson EducationDesign Patterns7 of 20 Understanding TrafficLight ’s State In what states can TrafficLight be? –when state is GoState, switch to StopState –when state is StopState, switch to GoState –can only change between two states — toggle What causes TrafficLight ’s state change? –changes whenever button is pressed (stimulus) –transition occurs when change() method is sent to TrafficLight (response) So each state knows which state is next –can make getNextState() method that returns the other state –TrafficLight starts in StopState so that when button is pressed, light turns green –no real final state GoStateStopState Turn TrafficLight to GoState Turn TrafficLight to StopState
© 2006 Pearson EducationDesign Patterns8 of 20 Implementing a Simple State Pattern State Pattern means that: –we have different states that respond to the same methods in different ways (POLYMORPHISM!) Let’s define state superclass: –generalizes methods for its subclasses (each particular concrete state) to follow First, revisit class diagram for TrafficLight object, with more details –TrafficLight contains LightChangeButton and LightState –LightChangeButton and LightState know about TrafficLight that contains them TrafficLight LightStateLightLightChangeButton
© 2006 Pearson EducationDesign Patterns9 of 20 Implementing a Simple State (cont.) Note, according to state pattern: –TrafficLight DOES NOT CARE what state it’s in! TrafficLight just knows: –what the state can respond to (through the LightState superclass) –about the particular current state (i.e., has a reference to it) so that it can delegate to it In this case, contained instances need a reference back to object containing them Note, these implementation details were not reflected in our State Diagram –it models only features pertinent to changing behavior
© 2006 Pearson EducationDesign Patterns10 of 20 Implementing State Hierarchy States must be able to be used interchangeably –TrafficLight can be in two different states one state turns light green when button pressed one state turns light red when button pressed –each state must be able to switch to other one Use inheritance and polymorphism –generic superclass sets policy for subclasses to fill in can handle() response as appropriate can getNextState() to change which state will handle next response –concrete state subclasses define actual behavior (but add no additional behaviors) –then TrafficLight will hold reference of generic superclass’ type that actually refers to state subclass
© 2006 Pearson EducationDesign Patterns11 of 20 LightState Superclass Implementing the abstract superclass –each state needs to know about the TrafficLight it affects –handle() and getNextState() are abstract Why have protected instance variable? –subclasses need to have access to traffic light –protected because all subclasses need access TrafficLight contains a LightState Note: LightState does not contain TrafficLight, but only references it package Demos.PatternsLecture.TrafficLight; abstract public class LightState { protected TrafficLight _trafficLight; public LightState(TrafficLight light) { _trafficLight = light; } abstract public void handle(); abstract public LightState getNextState(); } // end of class LightState
© 2006 Pearson EducationDesign Patterns12 of 20 GoState Subclass uses _trafficLight reference to call go() returns reference to a new StopState Why is _trafficLight a protected instance in LightState superclass? –_trafficLight is reference to TrafficLight that contains this state –all states need to communicate with that light –LightState superclass is abstract and does not know how to do the work (I.e. handle() and getNextState() ) only subclasses can, in their own way, do the work, so they need access to _trafficLight package Demos.PatternsLecture.TrafficLight; public class GoState extends LightState { public GoState(TrafficLight newTrafficLight) { super(newTrafficLight); } public void handle() { /** * Note: _trafficLight is a protected variable * in LightState superclass, thus accessible * here. */ _trafficLight.stop(); } public LightState getNextState() { return new StopState(_trafficLight); } } // end of class GoState
© 2006 Pearson EducationDesign Patterns13 of 20 StopState Subclass This one is almost the same –uses _trafficLight reference to stop() –returns reference to a new GoState Very similar to GoState, but cannot factor anything else out –same constructor, but cannot inherit constructors –handle() differs in one method in both classes –getNextState() also differs only in one method –this phenomenon is common in small helper classes like states package Demos.PatternsLecture.TrafficLight; public class StopState extends LightState { public StopState(TrafficLight newTrafficLight) { super(newTrafficLight); } public void handle() { _trafficLight.go(); } public LightState getNextState() { return new GoState(_trafficLight); } } // end of class StopState
© 2006 Pearson EducationDesign Patterns14 of 20 Implementing TrafficLight What are properties of TrafficLight ? –contains a LightChangeButton and Light s –uses state objects to determine response to change() message What value should variables have initially? –state can be either StopState or GoState –spec says light should go() first time LightChangeButton is pressed –so StopState should be first state public class TrafficLight extends JPanel { private Light _top, _bottom; private JButton _lightChangeButton; private LightState _state; public TrafficLight() { super( new GridLayout(0, 1) ); _top = new Light(); _bottom = new Light(); _lightChangeButton = new LightChangeButton(this); this.stop(); _state = new StopState( this ); this.add(top); this.add(_bottom); this.add(_lightChangeButton); this.add(new QuitButton()); } // continued
© 2006 Pearson EducationDesign Patterns15 of 20 Implementing TrafficLight (cont.) Want change() method to delegate its response to current state, then transition to next state –call _state ’s handle() method to get response –call _state ’s getNextState() method to find next state // continuation of class TrafficLight public void go() { _top.setLight(Color.black); _bottom.setLight(Color.green); } public void stop() { _top.setLight(Color.red ); _bottom.setLight(Color.black); } public void change() { _state.handle(); _state = _state.getNextState(); } } // end of class TrafficLight
© 2006 Pearson EducationDesign Patterns16 of 20 TrafficLight Explanation How does this work? –Initially, _state.handle() switches light to green –then _state.getNextState() returns GoState –so _state = state.getNextState() replaces current state ( StopState ) with new state ( GoState ) –next time _state.handle() is sent, it will make traffic light red. –thus, change() toggles traffic light’s current state
© 2006 Pearson EducationDesign Patterns17 of 20 LightChangeButton Now we are done with the hard stuff –just need to define LightChangeButton, Light, and Frame LightChangeButton is simple: –just get reference to TrafficLight and create an inner listener class to tell the TrafficLight to change on actionPerformed public class LightChangeButton extends JButton { private TrafficLight _light; public LightChangeButton(TrafficLight light) { super("Change" ); _light = light; this.addActionListener(new LightChangeListener()); } private class LightChangeListener implements java.awt.event.ActionListener { public void actionPerformed( java.awt.event.ActionEvent e) { _light.change(); } } }
© 2006 Pearson EducationDesign Patterns18 of 20 Light Light class is really just an ellipse –but need a DrawingPanel to contain it –Light class is DrawingPanel that encapsulates ColorEllipse –provides methods for the changing the ellipse’s color package Demos.PatternsLecture.TrafficLight; public class Light extends JPanel { private gfx.ColorEllipse _ellipse; public Light() { super(null, true); this.setDimension( new java.awt.Dimension(200, 200)); this.setBackground(java.awt.Color.white); _ellipse = new gfx.ColorEllipse(this); _ellipse.setSize(this.getSize().width, this.getSize().height); _ellipse.setColor(java.awt.Color.black); } public void setLight(java.awt.Color color) { _ellipse.setColor(color); // only time this panel needs to repaint, // so do it here. this.repaint(); } }// paintComponent() elided
© 2006 Pearson EducationDesign Patterns19 of 20 Frame Same as almost every other JFrame package Demos.PatternsLecture.TrafficLight; public class App extends JFrame { private TrafficLight _trafficLight; public App() { super(“Traffic Light”); this.setDefaultCloseOperation(EXIT_ON_CLOS E); _trafficLight = new TrafficLight(this); this.add(_trafficLight); this.pack(); this.setVisible(true); } public static void main( String[] argv ) { App app = new App(); } } // end of class App
© 2006 Pearson EducationDesign Patterns20 of 20 Review of State Pattern Generic structure of State Pattern: Context represents our TrafficLight –public method request() is handled by state request() represented by our change() –AbstractState subclasses handle request and then change context’s state to next with getNextState() –our _state references GoState or StopState AbstractState represents LightState –what if we wanted to generalize this to models with multiple transitions from a state? have multiple handle() methods or give more information to both methods (PARAMETERS!) Context request() {_state.handle();} AbstractState handle() getNextState() ConcreteStateA handle() getNextState() ConcreteStateB handle() getNextState()