Observer and Decorator Pattern


Published on

This is Class 5 on a 6 week course I taught on Software Design Patterns.

This course discusses the Observer and Decorator patterns.

Class based on "Head First Design Patterns."

Published in: Technology, Business
  • Be the first to comment

  • Be the first to like this

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • 13 November 2008
  • Interface breaks. By value. The Observer needs to have it’s own version of the state data. Problem is that the Subject sends a lot more information that needed. We can resolve by sending a null value for data that has not changed. 13 November 2008
  • 1. No. We would need to cast the subject to a specific subject so that we can get the properties that we want. This ties our Observer to a very specific Subject. Note with the Push model, the Observer did not need to know about the Subject data. 13 November 2008
  • 1. reigsterObserver removeObserver notifyObservers 2. ArrayList observers 3. Initialize the ArrayList of observers 13 November 2008
  • Temperature, humidity, and pressure aren’t part of a generic subject. 13 November 2008
  • The Subject passed on a reference to itself. The SubjectEvent needs to pass the Subject as well. The SubjectEvent needs to tell the Observer the name of the event. 13 November 2008
  • Observer = Search Screen. Just one observer Multiple Subjects 13 November 2008
  • Observers = Each Child Node Subject = Parent Node 13 November 2008
  • Observer and Decorator Pattern

    1. 1. Design Patterns 05/28/10 Week 5: Observer and Decorator Jonathan Simon [email_address]
    2. 2. Weather Monitoring Application <ul><li>Weather Station which monitors humidity, temperature, and pressure. </li></ul><ul><li>There are three different displays for showing the information from the Weather Station </li></ul><ul><ul><li>Current Conditions </li></ul></ul><ul><ul><li>Weather Stats </li></ul></ul><ul><ul><li>Forecast </li></ul></ul><ul><li>Goal: </li></ul><ul><ul><li>Changes in the Weather Station must update all three displays. </li></ul></ul><ul><ul><li>In addition, need capability to add additional displays in the future. </li></ul></ul>05/28/10
    3. 3. Observer Pattern <ul><li>GoF Intent: “Defines a one-to-many dependency between objects so that when one object changes state , all of its dependents are notified and updated automatically.” </li></ul><ul><li>pgs 38-56 provide a good background on the pattern. </li></ul>05/28/10
    4. 4. Definitions <ul><li>Subject </li></ul><ul><ul><li>Sends a notification message to one or many observers when there is a change in state. </li></ul></ul><ul><ul><li>Along with the message, provides information on the state that has changed. </li></ul></ul><ul><li>Observers – The objects that want to be notified about changes in the Subject’s state </li></ul>05/28/10
    5. 5. Interfaces 05/28/10 Contains signatures for registering, removing, and notifying observers. Contains Update method so that information can be sent from Subject to Observer.
    6. 6. WeatherData (Subject) Questions: Which field is used for storing the list of Observers? How does an Observer add itself to this list? The fields for humidity, pressure, and temperature represent the state of the Subject.
    7. 7. WeatherData (Subject; Pt 1) <ul><li>public class WeatherData : ISubject { </li></ul><ul><li>//Fields that represent State </li></ul><ul><li>private float temperature; </li></ul><ul><li>private float humidity; </li></ul><ul><li>private float pressure; </li></ul><ul><li>public void SetMeasurements(float temperature, </li></ul><ul><li>float humidity, float pressure) { </li></ul><ul><li>//Not Shown: set field variables based on parameters </li></ul><ul><li>MeasurementsChanged(); </li></ul><ul><li>} </li></ul><ul><li>public void MeasurementsChanged() { </li></ul><ul><li>NotifyObserver(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Observers are notified since state has changed.
    8. 8. WeatherData (Subject; Pt2) <ul><li>public WeatherData() { </li></ul><ul><li>observers = new ArrayList(); </li></ul><ul><li>} </li></ul><ul><li>public void RegisterObserver(IObserver o) { </li></ul><ul><li>observers.Add(o); </li></ul><ul><li>} </li></ul><ul><li>public void RemoveObserver(IObserver o) { </li></ul><ul><li>int i = observers.IndexOf(o); </li></ul><ul><li>if(i >= 0) observers.Remove(o); </li></ul><ul><li>} </li></ul><ul><li>public void NotifyObserver() { </li></ul><ul><li>foreach(IObserver observer in observers) observer.Update(temperature,humidity,pressure); </li></ul><ul><li>} </li></ul>Here is how the Subject sends information to all Observers
    9. 9. Current Conditions Display (Observer) Note that the individual Observer is composed of the Subject. So the Subjects has a reference to all Observers…and each Observer has a reference to a Subject. Questions: What method on this Observer is called by the Subject when data is changed?
    10. 10. CurrentConditionsDisplay (Observer) <ul><li>public class CurrentConditionsDisplay : IObserver, IDisplayElement { </li></ul><ul><li>private ISubject weatherData; </li></ul><ul><li>public CurrentConditionsDisplay( ISubject weatherData ) </li></ul><ul><li>{ </li></ul><ul><li>this.weatherData = weatherData; </li></ul><ul><li>weatherData.RegisterObserver(this); </li></ul><ul><li>} </li></ul><ul><li>public void Update(float temperature, float humidity, float pressure) </li></ul><ul><li>{ </li></ul><ul><li>//Store information so that it can be displayed </li></ul><ul><li>//This class contains its own version of the 3 </li></ul><ul><li>//state variables. </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    11. 11. WeatherStation <ul><li>//Create Subject </li></ul><ul><li>WeatherData weatherdata = new WeatherData(); </li></ul><ul><li>//Create Observer </li></ul><ul><li>CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherdata); </li></ul><ul><li>//Create Observer </li></ul><ul><li>StatisticsDisplay statDisplay = new StatisticsDisplay(weatherdata); </li></ul><ul><li>weatherdata.SetMeasurements(80, 65, 30.4f); </li></ul><ul><li>weatherdata.SetMeasurements(82, 70, 29.2f); </li></ul>05/28/10
    12. 12. Lab - Push <ul><li>public void NotifyObserver() { </li></ul><ul><li> foreach(IObserver observer in observers) </li></ul><ul><li>observer.Update(temperature,humidity,pressure); </li></ul><ul><li>} </li></ul><ul><li>This is called a “Push” model because the Subject is “pushing” information to the Observer(s). </li></ul><ul><li>Question 1: What happens if we need to add a 4 th state variable? Is there another alternative to sending all of these state variables? </li></ul><ul><li>Question 2: In general, should we push state by reference or by value? </li></ul><ul><li>Question 3: The three state variables in this example are rather simple (three strings). Let’s say they are actually more complex objects that take up a lot of memory. The Subject only changes one state variable. What problem may we have? How can we resolve it? </li></ul>
    13. 13. Lab - Pull <ul><li>An alternative to the “Push” model is the “Pull” model. The Observer pulls the information that is needed from the Subject. We can make a simple change to the IObserver interface: </li></ul><ul><li>public interface IObserver { </li></ul><ul><li>void Update(ISubject subject); </li></ul><ul><li>} </li></ul><ul><li>Question 1: A specific Observer using this interface would need to query the Subject to get specific information about that Subject. Can we use the ISubject interface? </li></ul><ul><li>Question 2: Let’s say CurrentConditionsDisplay gets notified that WeatherData has a change. It goes to retrieve the new temperature…but right before it does, WeatherData gets another temperature change and is reset to the original temperature value. Does the Observer notice any real change? How can we resolve? </li></ul>
    14. 14. Lab – Refactor WeatherData <ul><li>When class resumes, we will be going through a major refactoring of the WeatherData example in the book. Please consider these question in preparation for this exercise: </li></ul><ul><li>Look at WeatherData example on pg58. Which pieces of information is really specific to Weather? Which part is specific to the whole Subject/Observer relationship? </li></ul><ul><li>Look at CurrentConditionsDisplay on pg 59. Which pieces is specific to Weather? To the Subject/Observer relationship? </li></ul>05/28/10
    15. 15. Refactoring WeatherData <ul><li>We want to create an infrastructure so that we can reuse Subject and Observer functionality. </li></ul><ul><li>Also, according to the Single Responsibility Principle, the class WeatherData is doing too much! </li></ul><ul><li>What two general options can we consider to break this object up? </li></ul>05/28/10
    16. 16. Subject <ul><li>Let’s create an abstract class called “Subject” with some default implementation. (We will also create a class “Observer” that also has some default implementation). </li></ul><ul><li>Looking at the WeatherData (pg58), which methods in WeatherData should be moved to Subject? </li></ul><ul><li>Which fields should be moved to Subject? </li></ul><ul><li>What should the constructor of Subject initialize? </li></ul>05/28/10
    17. 17. Subject <ul><li>public abstract class Subject { </li></ul><ul><li>private List<Observer> observers; </li></ul><ul><li> public Subject() { </li></ul><ul><li>observers = new List<Observer>(); } </li></ul><ul><li>public void RegisterObserver(Observer o) { .. } </li></ul><ul><li> public void RemoveObserver(Observer o) { .. } </li></ul><ul><li>public void NotifyObserver() </li></ul><ul><li>{ </li></ul><ul><li>foreach (Observer observer in observers) </li></ul><ul><li>observer.Update(temperature, humidity, pressure); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 What is wrong with NotifyObserver??
    18. 18. Subject <ul><li>public abstract class Subject { </li></ul><ul><li>private List<Observer> observers; </li></ul><ul><li>public Subject() { </li></ul><ul><li>observers = new List<Observer>(); </li></ul><ul><li>} </li></ul><ul><li>public void RegisterObserver(Observer o) { } </li></ul><ul><li>public void RemoveObserver(Observer o) { } </li></ul><ul><li>public void NotifyObserver() </li></ul><ul><li>{ </li></ul><ul><li>foreach (Observer observer in observers) </li></ul><ul><li>observer.Update(this); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 Is this implying Push or Pull?
    19. 19. Observer <ul><li>Looking at CurrentConditionsDisplay (pg59), we should abstract out the registering of the Observer to a Subject. </li></ul><ul><ul><li>What kind of argument do we need to pass in the Observer constructor? </li></ul></ul><ul><ul><li>Within the Observer constructor, what method should we call on the Subject? </li></ul></ul><ul><ul><li>How can we enforce that the inherited classes use this constructor?? </li></ul></ul><ul><li>What method should Observer provide? </li></ul>05/28/10
    20. 20. Observer <ul><li>public abstract class Observer { </li></ul><ul><li>public Observer(Subject subject) </li></ul><ul><li>{ </li></ul><ul><li>subject.RegisterObserver(this); </li></ul><ul><li>} </li></ul><ul><li> private Observer() { } </li></ul><ul><li> public abstract void Update(Subject subject); </li></ul><ul><li>} </li></ul>05/28/10
    21. 21. So far… 05/28/10 NotifyObserver will loop through each Observer and call Update() and pass a reference of itself Observer registers itself with the Subject
    22. 22. Concrete Subject <ul><li>What class should WeatherData inherit from? </li></ul><ul><li>How will the Observer get information from our Concrete Subject?? </li></ul><ul><ul><li>Remember: We are using Pull model. Hint on previous Pull slide.. </li></ul></ul><ul><li>How will WeatherData tell the Observers that there is an update? </li></ul>05/28/10
    23. 23. ConcreteSubject <ul><li>public class WeatherData : Subject { </li></ul><ul><li>//Not Shown: the three fields </li></ul><ul><li>public float getTemp() { return this.temperature; } </li></ul><ul><li>public float getHumidity() { return this.humidity; } </li></ul><ul><li>public float getPressure() { return this.pressure; } </li></ul><ul><li>public void SetMeasurements(…) { </li></ul><ul><li>//Set data here </li></ul><ul><li>measurementsChanged(); //which calls NotifyObservers </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    24. 24. Concrete Observer <ul><li>What data needs to be passed in the Constructor? </li></ul><ul><li>How will Update get access to the specific properties for the Subject?? </li></ul>05/28/10
    25. 25. ConcreteObserver <ul><li>public class CurrentConditionsDisplay : Observer, IDisplayElement { </li></ul><ul><li>private WeatherData weather; </li></ul><ul><li> //Fields Not shown </li></ul><ul><li>public CurrentConditionsDisplay(WeatherData wd) : base(wd) { </li></ul><ul><li> = wd; </li></ul><ul><li>} </li></ul><ul><li> public override void Update(Subject subject) { </li></ul><ul><li>if ( subject == ) </li></ul><ul><li>{ </li></ul><ul><li>this.temperature =; </li></ul><ul><li>this.humidity =; </li></ul><ul><li>this.pressure =; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    26. 26. Client Code <ul><li>//Create Subject </li></ul><ul><li>WeatherData weatherdata = new WeatherData(); </li></ul><ul><li>//Create Observers (with reference to Subject) </li></ul><ul><li>CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherdata); </li></ul><ul><li>ForcastDisplay forcastDisplay = new ForcastDisplay(weatherdata); </li></ul><ul><li>//Tell Subject to change state </li></ul><ul><li>weatherdata.SetMeasurements(80, 65, 30.4f); </li></ul>05/28/10
    27. 27. The Big Picture 05/28/10
    28. 28. In Class Lab <ul><li>Our Subject class has one Update function that is called when there is a change in state. But what if we want our Subject to have multiple Update functions? For example, one Update function could represent a change in state for fields A, B, and C. Another Update function could represent a change in state for fields X, Y, and Z. </li></ul><ul><li>Question 1: Will our current implementation of Subject support multiple update events? </li></ul><ul><li>Question 2: What if we just add another Update() function to Subject? What is the problem with that? </li></ul><ul><li>Question 3: Consider this..are our Observers interested in the Subject itself..or in an actual event notifying change? </li></ul>05/28/10
    29. 29. Multiple Events <ul><li>Currently, the Observers want to be notified when there is a change in the weather measurements(Temperature, Humidity, Pressure). </li></ul><ul><li>The Subject (WeatherData) now gets the capability to store information about the probability of a disaster occurring. This is defined by: </li></ul><ul><ul><li>float HurricaneProbability </li></ul></ul><ul><ul><li>float TornadoProbability </li></ul></ul><ul><li>The Subject needs two notification events: </li></ul><ul><ul><li>WeatherMeasureChanged </li></ul></ul><ul><ul><li>DisasterProbabiltyChanged </li></ul></ul>05/28/10
    30. 30. Problem <ul><li>The Subject (WeatherData) only has one notification event. We have a one-to-one relationship between Subject and Event. </li></ul><ul><li>We need a one-to-many relationship. One Subject can have one or more events! </li></ul>05/28/10
    31. 31. Analysis <ul><li>Our current Subject has a one-to-many relationship with Observers. </li></ul><ul><li>Subject  Observer1 </li></ul><ul><li>  Observer2 </li></ul><ul><li>  Observer3 </li></ul><ul><li>A subject has one event. So we can think about this as: </li></ul><ul><li>Subject  Event  Observer1 </li></ul><ul><li>  Observer2 </li></ul><ul><li>  Observer3 </li></ul>05/28/10
    32. 32. Analysis <ul><li>We would like our Subject to contain multiple events. </li></ul><ul><li>Subject  Event1 </li></ul><ul><li>  Event2 </li></ul><ul><li>  Event3 </li></ul><ul><li>Therefore, we need a structure like the following: </li></ul><ul><li>Subject  Event1 </li></ul><ul><li>  Observer1 </li></ul><ul><li>  Observer2 </li></ul><ul><li>  Event2 </li></ul><ul><li> Observer1 </li></ul><ul><li> Observer3 </li></ul>05/28/10
    33. 33. Subject (Current Implementation) 05/28/10 Our Subject class contains the one notification event. Our ConcreteSubject gets the notification event by inheritance. We want our ConcreteSubject to contain multiple events. Does Inheritance make sense??? Would could we use instead?
    34. 34. Subject/SubjectEvent 05/28/10 This class represents a specific event of the Subject.
    35. 35. SubjectEvent 05/28/10 Now the SubjectEvent, not Subject, contains a reference to all of the Observers who are interested in being notified.
    36. 36. Subject/SubjectEvent 05/28/10 The constructor of WeatherData takes a SubjectEvent as parameter.
    37. 37. WeatherData <ul><li>public class WeatherData { </li></ul><ul><li>private SubjectEvent subEvent; </li></ul><ul><li>public WeatherData( SubjectEvent subEvent ) { </li></ul><ul><li>this.subEvent = subEvent; </li></ul><ul><li>} </li></ul><ul><li>public void SetMeasurements(…) </li></ul><ul><li>{ </li></ul><ul><li>this.temperature = temperature; </li></ul><ul><li>this.humidity = humidity; </li></ul><ul><li>this.pressure = pressure; </li></ul><ul><li>this.subEvent.NotifyObserver(this); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    38. 38. SubjectEvent + Observers <ul><li>In our prior design, what information did the Subject pass on to the Observers? </li></ul><ul><li>In this design, should the SubjectEvent pass the same information to the Observers? </li></ul><ul><li>What if an Observer is listening to two different events on the same Subject? The Observer will want to know which data to pull based on the Event that notified it. </li></ul><ul><ul><li>So, what does the SubjectEvent also need to tell the Observers who are listening to it? </li></ul></ul>05/28/10
    39. 39. SubjectEvent 05/28/10 Added name parameter to the constructor and storing it in eventName Field.
    40. 40. SubjectEvent <ul><li>public class SubjectEvent { </li></ul><ul><li> private List<Observer> observers; </li></ul><ul><li>private string eventName; </li></ul><ul><li>public SubjectEvent( string name ) { </li></ul><ul><li>observers = new List<Observer>(); </li></ul><ul><li>eventName = name; </li></ul><ul><li> } </li></ul><ul><li>public void NotifyObserver(object subject) { </li></ul><ul><li>foreach (Observer observer in observers) </li></ul><ul><li>observer.Update(subject, eventName); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 Cheating
    41. 41. Observer <ul><li>In the prior design, the Observer was constructed with a reference to the Subject. In this design, what should we pass in the constructor instead? </li></ul><ul><li>What should the signature of the Update() function look like? </li></ul>05/28/10
    42. 42. Observer <ul><li>public abstract class Observer { </li></ul><ul><li>public Observer(SubjectEvent subEvent) { </li></ul><ul><li>subEvent.RegisterObserver(this); </li></ul><ul><li>} </li></ul><ul><li>public abstract void Update(object data, </li></ul><ul><li> string eventName); </li></ul><ul><li>private Observer() { } </li></ul><ul><li>} </li></ul>05/28/10
    43. 43. CurrentConditionsDisplay <ul><li>public override void Update(object data, string name) { </li></ul><ul><li> if (data is WeatherData) { </li></ul><ul><li>WeatherData weather = (WeatherData)data; </li></ul><ul><li>if (name.Equals(&quot;WeatherChanged&quot;)) </li></ul><ul><li>{ </li></ul><ul><li>this.temperature = weather.getTemp(); </li></ul><ul><li>this.humidity = weather.getHumidity(); </li></ul><ul><li>this.pressure = weather.getPressure(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    44. 44. Big Picture 05/28/10
    45. 45. Client Code <ul><li>//Create SubjectEvent..with specific event name </li></ul><ul><li>SubjectEvent event1 = new SubjectEvent(&quot;WeatherChanged&quot;); </li></ul><ul><li>//Create Observers for that event </li></ul><ul><li>CurrentConditionsDisplay observer1 = new CurrentConditionsDisplay(event1); </li></ul><ul><li>ForcastDisplay observer2 = new ForcastDisplay(event1); </li></ul><ul><li>//Create Subject (and pass in reference to the event) </li></ul><ul><li>WeatherData subject = new WeatherData(event1); </li></ul>05/28/10
    46. 46. Not done yet.. <ul><li>WeatherData just contains one event. Now we want to add a second event. </li></ul><ul><li>public class WeatherData { </li></ul><ul><li> SubjectEvent weatherEvent; </li></ul><ul><li>SubjectEvent disasterEvent ; </li></ul><ul><li>public WeatherData(SubjectEvent weatherEvent, SubjectEvent disasterEvent) { </li></ul><ul><li>this.weatherEvent = weatherEvent; </li></ul><ul><li>this.disasterEvent = disasterEvent; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    47. 47. WeatherData (cont) <ul><li>public void WeatherMeasurementsChanged() </li></ul><ul><li>{ </li></ul><ul><li>this.weatherEvent.NotifyObserver(this); </li></ul><ul><li>} </li></ul><ul><li>public void DisasterProbabilityChanged() </li></ul><ul><li>{ </li></ul><ul><li>this.disasterEvent.NotifyObserver(this); </li></ul><ul><li>} </li></ul>05/28/10
    48. 48. ConcreteObserver <ul><li>public override void Update(object data, string name) { </li></ul><ul><li>if (data is WeatherData) </li></ul><ul><li>{ </li></ul><ul><li>WeatherData weather = (WeatherData)data; </li></ul><ul><li>if (name.Equals(&quot;WeatherChanged&quot;)) </li></ul><ul><li> { //do weather stuff } </li></ul><ul><li>else if (name.Equals(&quot;DisasterComing&quot;)) </li></ul><ul><li>{ </li></ul><ul><li>this.hurricaneProbability = weather.getHurricaneProb(); </li></ul><ul><li>this.tornadoProbability = weather.getTornadoProb(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    49. 49. Client Code <ul><li>//Create Observers </li></ul><ul><li>CurrentConditionsDisplay observer1 = new CurrentConditionsDisplay(); </li></ul><ul><li>ForcastDisplay observer2 = new ForcastDisplay(); </li></ul><ul><li>//Create SubjectEvents </li></ul><ul><li>SubjectEvent se1 = new SubjectEvent(&quot;WeatherChanged&quot;); </li></ul><ul><li>se1.RegisterObserver(observer1); </li></ul><ul><li>se1.RegisterObserver(observer2); </li></ul><ul><li>SubjectEvent se2 = new SubjectEvent(&quot;DisasterComing&quot;); </li></ul><ul><li>se2.RegisterObserver(observer2); </li></ul><ul><li>//Create Subject </li></ul><ul><li>WeatherData wd = new WeatherData(se1, se2) </li></ul>05/28/10
    50. 50. Other Problems Arise.. <ul><li>Problem #1: Let’s say CurrentConditionsDisplay gets notified that WeatherData has a change in temperature. It then performs some magical actions, which result in WeatherData getting another change in temperature. What is the impact? </li></ul><ul><li>Problem #2: WeatherData objects are created for VA, MD, and DC regions. The Observers should only be updated when all three WeatherData objects have an internal change. </li></ul>05/28/10
    51. 51. Change Manager <ul><li>Both of these problems can be solved with another objected called the ChangeManager. </li></ul><ul><li>This object is an example of Mediator Pattern </li></ul><ul><ul><li>GoF Intent: “Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.” </li></ul></ul><ul><li>It can handle complex update strategies. </li></ul><ul><li>It can also be a Singleton! </li></ul>05/28/10
    52. 52. Features of the Change Manager <ul><li>Contains a mapping of Subject-to-Observers. </li></ul><ul><li>Provides an interface for registering Subject to Observers. </li></ul><ul><li>Eliminates the need for Subject to maintain references to its Observers (and vica versa). </li></ul><ul><li>Defines a specific update strategy. </li></ul>05/28/10
    53. 53. Addressing Problem #2 <ul><li>ChangeManager can store the relationship between each Subject to Observers. For example: </li></ul><ul><ul><li>Subject : WeatherData (DC) </li></ul></ul><ul><ul><li>Observer(s): CurrentConditions, ForcastDisplay </li></ul></ul><ul><ul><li>Subject : WeatherData (VA) </li></ul></ul><ul><ul><li>Observer(s): CurrentConditions </li></ul></ul><ul><ul><li>Subject : WeatherData (MD) </li></ul></ul><ul><ul><li>Observer(s): CurrentConditions, StatisticsDisplay </li></ul></ul>05/28/10
    54. 54. Addressing Problem #2 (cont) <ul><li>When WeatherData(DC) has an internal update, it sends a message to ChangeManager to notify observers. </li></ul><ul><li>The ChangeManager contains an internal state that indicates if all three WeatherData objects have indicated a recent change. </li></ul><ul><li>If ChangeManager determines that all three WeatherData objects have indicted a change, it sends a message to each Observer associated with each Subject. </li></ul>05/28/10
    55. 55. Using Event Infrastructure <ul><li>All of these examples have been using the Classical Definition of the Observer pattern. </li></ul><ul><li>There are language specific features of C# and Java that can be used to make this pattern much simpler to use. </li></ul><ul><li>Using the Event infrastructure: </li></ul><ul><ul><li>RegisterObserver  Register Event with Handler </li></ul></ul><ul><ul><li>RemoveObserver  Unregister Event with Handler </li></ul></ul><ul><ul><li>NotifyObserver  Raise Event </li></ul></ul><ul><ul><li>Special data about the Event can be passed as Event argument. </li></ul></ul>05/28/10
    56. 56. Real World Examples <ul><li>Problem #1 </li></ul><ul><ul><li>Search screen that lists documents with a Status per document </li></ul></ul><ul><ul><li>From the screen, user can open one or more documents. </li></ul></ul><ul><ul><li>When a document is opened, the status is changed. </li></ul></ul><ul><ul><li>User closes document, the search screen still displays the old status. </li></ul></ul><ul><li>Who are the Observers? </li></ul><ul><li>Who are the Subjects? </li></ul>05/28/10
    57. 57. Solution #1 <ul><li>Search Screen = Observer (Just one) </li></ul><ul><li>Each opened document = Subject </li></ul><ul><li>So we have one Observer with multiple Subjects. </li></ul><ul><li>When a document is opened, the Search screen (Observer) must register itself with the Document (Subject). </li></ul><ul><li>Subject must broadcast a notify message when its Status state changes. </li></ul><ul><li>Observer, upon receiving the message, can update its state and display the updated status. </li></ul><ul><li>When Subject closes, the Observer must unregister itself with the Subject. (The Subject needs to tell the Observer that it is closing) </li></ul>
    58. 58. Problem #2 <ul><li>Document structure that contains Parent and Child nodes. </li></ul><ul><li>When a Parent Node changes, all of the Child Nodes need to be re-validated. </li></ul><ul><li>Currently, we simply re-validate all Child Nodes for all Parents. There is no direct relationship between a change in Parent affecting the Child Nodes. </li></ul><ul><li>Who are Observers? Subjects? </li></ul>05/28/10
    59. 59. Solution #2 <ul><li>Observers – All Child Nodes for a single Parent </li></ul><ul><li>Subject – Single Parent Node </li></ul><ul><li>So multiple Observers with one Subject. </li></ul><ul><li>All Observers must register themselves with a data change event for the Subject. </li></ul><ul><li>When the Subject changes it state, a data change notification is sent. </li></ul><ul><li>Each Subject re-validates itself. </li></ul><ul><li>Also: See Composite Pattern. </li></ul>
    60. 60. Problem #3 <ul><li>A Business Object is composed of multiple Properties. </li></ul><ul><li>Each property has one or more validation rules associated with it. </li></ul><ul><li>When a Business Object is loaded, each validation rule on each property is executed. </li></ul>05/28/10
    61. 61. Problem #3 (Cont) <ul><li>Property A </li></ul><ul><ul><li>Rule #1: Must have a value </li></ul></ul><ul><ul><li>Rule #2: Must be a valid look-up value in the database (Precondition: Must have a value) </li></ul></ul><ul><ul><li>Rule #3: Must contain a valid combination with Property B and C. (Preconditions: Must have a value; must be valid in db) </li></ul></ul><ul><li>Problem: </li></ul><ul><ul><li>These three rules have no relationship with each other…yet there seems to be a logical relationship. </li></ul></ul><ul><ul><li>Rules 2 and 3 perform duplication of logic in the pre-conditions. </li></ul></ul><ul><ul><li>There is no reason to run the expensive precondition logic of Rule #3 if Rule #2 is not valid (yet we do it anyway). </li></ul></ul>05/28/10
    62. 62. Solution #3 <ul><li>Change Manager. Let’s look at the internal mapping: </li></ul><ul><li>Mapping 1: </li></ul><ul><ul><li>Subject: Rule #1 </li></ul></ul><ul><ul><li>Observers: Rule #2, Rule #3 </li></ul></ul><ul><li>Mapping 2: </li></ul><ul><ul><li>Subject: Rule #2 </li></ul></ul><ul><ul><li>Observers: Rule #3 </li></ul></ul><ul><li>Note: Rule #2 is both a Subject and an Observer. </li></ul><ul><li>Note: Rule #3 depends on Rule #1 and Rule #2. It should not execute unless both send messages. This state would need to be managed by ChangeManager. </li></ul>
    63. 63. Solution #3 <ul><li>This can get complex very quickly. </li></ul><ul><li>This really may not be a practical solution at all. </li></ul><ul><li>If used, would focus on the rules that are the most expensive. (Performance Testing can help identify). </li></ul>05/28/10
    64. 64. Lab (Introduction to Decorator) <ul><li>We have a simple class for logging message and one implementation. </li></ul><ul><li>public class DefaultLogger { </li></ul><ul><li>public virtual void Log(string file, string msg) </li></ul><ul><li>{ </li></ul><ul><li>//Open File </li></ul><ul><li>//Write msg to file </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    65. 65. Lab <ul><li>A new requirement states that we need to extend the DefaultLogger to encrypt messages before we log. This can be done simply with inheritance: </li></ul><ul><li>public class EncryptedLogger : DefaultLogger { </li></ul><ul><li>public override void Log(string file, string msg) </li></ul><ul><li>{ </li></ul><ul><li>//Encrypt Message </li></ul><ul><li>//Call base functionality </li></ul><ul><li>base.Log(file, msg); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    66. 66. Lab <ul><li>We get another requirement that when logging, we need to compress the message, then encrypt it, then write to log. This can also be done easily with inheritance: </li></ul><ul><li>public class CompressLogger : EncryptedLogger { </li></ul><ul><li>public override void Log(string file, string msg) </li></ul><ul><li>{ </li></ul><ul><li>//Compress Message </li></ul><ul><li>//Call base functionality, which Encrypts and </li></ul><ul><li>//then writes basic functionlity </li></ul><ul><li>base.Log(file, msg); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    67. 67. Lab <ul><li>Now we get a requirement that we need to Compress the message..but then simply write it to the log file. No encryption is needed. </li></ul><ul><li>Using inheritance, what class would we need to inherit from? What problem do we have? </li></ul>05/28/10
    68. 68. Problem <ul><li>Inheritance statically defined an order of enhancing behavior. </li></ul><ul><li>We ran into an issue when we wanted more flexibility in adding behavior. </li></ul><ul><li>Using a Decorator, we can add (and remove) behavior at will! </li></ul>05/28/10
    69. 69. Solution <ul><li>public abstract class LoggerDecorator : DefaultLogger { </li></ul><ul><li>public override void Log(string file, string msg) { </li></ul><ul><li>base.Log(file, msg); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 This is our Decorator class. In this example, it is extending the class that we want to enhance with additional functionality.
    70. 70. EncryptedLogger <ul><li>public class EncryptedLogger : LoggerDecorator { </li></ul><ul><li>DefaultLogger dLogger; </li></ul><ul><li>public EncryptedLogger(DefaultLogger logger) </li></ul><ul><li>{ </li></ul><ul><li>this.dLogger = logger; </li></ul><ul><li>} </li></ul><ul><li>public override void Log(string file, string msg) </li></ul><ul><li>{ </li></ul><ul><li>//Do encryprted functionality </li></ul><ul><li>string encryptedMsg = msg; </li></ul><ul><li>Console.WriteLine(&quot;Encrpytion&quot;); </li></ul><ul><li>dLogger.Log(file, encryptedMsg); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 This is the object we want to extend
    71. 71. CompressionLogger <ul><li>public class CompressedLogger : LoggerDecorator { </li></ul><ul><li>DefaultLogger dLogger; </li></ul><ul><li>public CompressedLogger(DefaultLogger logger) </li></ul><ul><li>{ </li></ul><ul><li>this.dLogger = logger; </li></ul><ul><li>} </li></ul><ul><li>public override void Log(string file, string msg) </li></ul><ul><li>{ </li></ul><ul><li>//Do compressed logic </li></ul><ul><li>string compressMsg = msg; </li></ul><ul><li>Console.WriteLine(&quot;Compression&quot;); </li></ul><ul><li>dLogger.Log(file, compressMsg); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    72. 72. Client Code <ul><li>//Simple log </li></ul><ul><li>DefaultLogger logger1 = new DefaultLogger(); </li></ul><ul><li>logger1.Log(&quot;log1.txt&quot;, &quot;here is a message&quot;); </li></ul><ul><li>//Add encryption </li></ul><ul><li>EncryptedLogger eLogger = new EncryptedLogger(logger1); </li></ul><ul><li>eLogger.Log(&quot;log2.txt&quot;, &quot;encrypt this!&quot;); </li></ul><ul><li>//Add compression </li></ul><ul><li>CompressedLogger cLogger = new CompressedLogger(eLogger); </li></ul><ul><li>Logger.Log(&quot;log3.txt&quot;, &quot;compress this&quot;); </li></ul>05/28/10
    73. 73. Decorator <ul><li>GoF Intent: “Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.” </li></ul>05/28/10
    74. 74. Things to Note <ul><li>Composition, not Inheritance, was used to extend behavior. </li></ul><ul><li>No changes were made to the original class (DefaultLogger). </li></ul><ul><li>We could have provided a GUI so that the end user could specify the behaviors to use. </li></ul>05/28/10
    75. 75. Comparison to Other Patterns <ul><li>Strategy </li></ul><ul><ul><li>Good to use when we need to change the “guts” of an object. </li></ul></ul><ul><ul><li>Think of decorator as a way to change the “skin” of an object. Also with decorator, we can apply multiple enhancements on top of each other. </li></ul></ul><ul><li>Adapter </li></ul><ul><ul><li>Just changes the interface of an object. </li></ul></ul><ul><ul><li>A decorator will enhance behavior of an object. </li></ul></ul>05/28/10
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.