observer and decorator pattern

75
05/21/22 1 Design Patterns Week 5: Observer and Decorator Jonathan Simon [email protected]

Upload: jonathan-simon

Post on 15-Dec-2014

2.747 views

Category:

Technology


17 download

DESCRIPTION

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."

TRANSCRIPT

Page 1: Observer and Decorator Pattern

04/10/23 1

Design Patterns

Week 5: Observer and Decorator

Jonathan [email protected]

Page 2: Observer and Decorator Pattern

Weather Monitoring Application Weather Station which monitors humidity, temperature,

and pressure.

There are three different displays for showing the information from the Weather Station Current Conditions Weather Stats Forecast

Goal: Changes in the Weather Station must update all three displays. In addition, need capability to add additional displays in the

future.

204/10/23

Page 3: Observer and Decorator Pattern

Observer Pattern

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.”

pgs 38-56 provide a good background on the pattern.

304/10/23

Page 4: Observer and Decorator Pattern

Definitions

Subject Sends a notification message to one or many observers when

there is a change in state. Along with the message, provides information on the state that

has changed.

Observers – The objects that want to be notified about changes in the Subject’s state

404/10/23

Page 5: Observer and Decorator Pattern

Interfaces

504/10/23

Contains signatures for registering, removing, and notifying observers.

Contains Update method so that information can be sent from Subject to Observer.

Page 6: Observer and Decorator Pattern

WeatherData (Subject)

6

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.

Page 7: Observer and Decorator Pattern

WeatherData (Subject; Pt 1)public class WeatherData : ISubject {

//Fields that represent State

private float temperature;

private float humidity;

private float pressure;

public void SetMeasurements(float temperature,

float humidity, float pressure) {

//Not Shown: set field variables based on parameters

MeasurementsChanged();

}

public void MeasurementsChanged() {

NotifyObserver();

}

} 7

Observers are notified since state has changed.

Page 8: Observer and Decorator Pattern

WeatherData (Subject; Pt2)public WeatherData() {

observers = new ArrayList();

}

public void RegisterObserver(IObserver o) {

observers.Add(o);

}

public void RemoveObserver(IObserver o) {

int i = observers.IndexOf(o);

if(i >= 0) observers.Remove(o);

}

public void NotifyObserver() {

foreach(IObserver observer in observers) observer.Update(temperature,humidity,pressure);

}

8

Here is how the Subject sends information to all Observers

Page 9: Observer and Decorator Pattern

Current Conditions Display (Observer)

9

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?

Page 10: Observer and Decorator Pattern

CurrentConditionsDisplay (Observer)public class CurrentConditionsDisplay : IObserver, IDisplayElement {

private ISubject weatherData;

public CurrentConditionsDisplay(ISubject weatherData)

{

this.weatherData = weatherData;

weatherData.RegisterObserver(this);

}

public void Update(float temperature, float humidity, float pressure)

{

//Store information so that it can be displayed

//This class contains its own version of the 3

//state variables.

}

}10

04/10/23

Page 11: Observer and Decorator Pattern

WeatherStation

//Create Subject

WeatherData weatherdata = new WeatherData();

//Create Observer

CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherdata);

//Create Observer

StatisticsDisplay statDisplay = new StatisticsDisplay(weatherdata);

weatherdata.SetMeasurements(80, 65, 30.4f);

weatherdata.SetMeasurements(82, 70, 29.2f);

1104/10/23

Page 12: Observer and Decorator Pattern

Lab - Pushpublic void NotifyObserver() {

foreach(IObserver observer in observers)

observer.Update(temperature,humidity,pressure);

}

This is called a “Push” model because the Subject is “pushing” information to the Observer(s).

Question 1: What happens if we need to add a 4th state variable? Is there another alternative to sending all of these state variables?

Question 2: In general, should we push state by reference or by value?

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?

12

Page 13: Observer and Decorator Pattern

Lab - PullAn 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:

public interface IObserver {

void Update(ISubject subject);

}

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?

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?

13

Page 14: Observer and Decorator Pattern

Lab – Refactor WeatherData

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:

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?

Look at CurrentConditionsDisplay on pg 59. Which pieces is specific to Weather? To the Subject/Observer relationship?

1404/10/23

Page 15: Observer and Decorator Pattern

Refactoring WeatherData

We want to create an infrastructure so that we can reuse Subject and Observer functionality.

Also, according to the Single Responsibility Principle, the class WeatherData is doing too much!

What two general options can we consider to break this object up?

1504/10/23

Page 16: Observer and Decorator Pattern

Subject 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).

Looking at the WeatherData (pg58), which methods in WeatherData should be moved to Subject?

Which fields should be moved to Subject?

What should the constructor of Subject initialize?

1604/10/23

Page 17: Observer and Decorator Pattern

Subject public abstract class Subject {

private List<Observer> observers;

public Subject() {

observers = new List<Observer>();}

public void RegisterObserver(Observer o) { .. }

public void RemoveObserver(Observer o) { .. }

public void NotifyObserver()

{

foreach (Observer observer in observers)

observer.Update(temperature, humidity, pressure);

}

}

1704/10/23

What is wrong with NotifyObserver??

Page 18: Observer and Decorator Pattern

Subject public abstract class Subject {

private List<Observer> observers;

public Subject() {

observers = new List<Observer>();

}

public void RegisterObserver(Observer o) { }

public void RemoveObserver(Observer o) { }

public void NotifyObserver()

{

foreach (Observer observer in observers)

observer.Update(this);

}

}

1804/10/23

Is this implying Push or Pull?

Page 19: Observer and Decorator Pattern

Observer

Looking at CurrentConditionsDisplay (pg59), we should abstract out the registering of the Observer to a Subject.

What kind of argument do we need to pass in the Observer constructor?

Within the Observer constructor, what method should we call on the Subject?

How can we enforce that the inherited classes use this constructor??

What method should Observer provide?

1904/10/23

Page 20: Observer and Decorator Pattern

Observer

public abstract class Observer {

public Observer(Subject subject)

{

subject.RegisterObserver(this);

}

private Observer() { }

public abstract void Update(Subject subject);

}

2004/10/23

Page 21: Observer and Decorator Pattern

So far…

2104/10/23

NotifyObserver will loop through each Observer and call Update() and pass a reference of itself

Observer registers itself with the Subject

Page 22: Observer and Decorator Pattern

Concrete Subject

What class should WeatherData inherit from?

How will the Observer get information from our Concrete Subject?? Remember: We are using Pull model. Hint on previous Pull

slide..

How will WeatherData tell the Observers that there is an update?

2204/10/23

Page 23: Observer and Decorator Pattern

ConcreteSubject

public class WeatherData : Subject {

//Not Shown: the three fields

public float getTemp() { return this.temperature; }

public float getHumidity() { return this.humidity; }

public float getPressure() { return this.pressure; }

public void SetMeasurements(…) {

//Set data here

measurementsChanged(); //which calls NotifyObservers

}

}

2304/10/23

Page 24: Observer and Decorator Pattern

Concrete Observer

What data needs to be passed in the Constructor?

How will Update get access to the specific properties for the Subject??

2404/10/23

Page 25: Observer and Decorator Pattern

ConcreteObserver public class CurrentConditionsDisplay : Observer, IDisplayElement {

private WeatherData weather;

//Fields Not shown

public CurrentConditionsDisplay(WeatherData wd) : base(wd) {

this.weather = wd;

}

public override void Update(Subject subject) {

if (subject == this.weather)

{

this.temperature = this.weather.getTemp();

this.humidity = this.weather.getHumidity();

this.pressure = this.weather.getPressure();

}

}

}

2504/10/23

Page 26: Observer and Decorator Pattern

Client Code

//Create Subject

WeatherData weatherdata = new WeatherData();

//Create Observers (with reference to Subject)

CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherdata);

ForcastDisplay forcastDisplay = new ForcastDisplay(weatherdata);

//Tell Subject to change state

weatherdata.SetMeasurements(80, 65, 30.4f);

2604/10/23

Page 27: Observer and Decorator Pattern

The Big Picture

2704/10/23

Page 28: Observer and Decorator Pattern

In Class LabOur 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.

Question 1: Will our current implementation of Subject support multiple update events?

Question 2: What if we just add another Update() function to Subject? What is the problem with that?

Question 3: Consider this..are our Observers interested in the Subject itself..or in an actual event notifying change?

2804/10/23

Page 29: Observer and Decorator Pattern

Multiple Events Currently, the Observers want to be notified when there

is a change in the weather measurements(Temperature, Humidity, Pressure).

The Subject (WeatherData) now gets the capability to store information about the probability of a disaster occurring. This is defined by: float HurricaneProbability float TornadoProbability

The Subject needs two notification events: WeatherMeasureChanged DisasterProbabiltyChanged

2904/10/23

Page 30: Observer and Decorator Pattern

Problem

The Subject (WeatherData) only has one notification event. We have a one-to-one relationship between Subject and Event.

We need a one-to-many relationship. One Subject can have one or more events!

3004/10/23

Page 31: Observer and Decorator Pattern

AnalysisOur current Subject has a one-to-many relationship with

Observers.

Subject Observer1

Observer2

Observer3

A subject has one event. So we can think about this as:

Subject Event Observer1

Observer2

Observer3

3104/10/23

Page 32: Observer and Decorator Pattern

AnalysisWe would like our Subject to contain multiple events.

Subject Event1

Event2

Event3

Therefore, we need a structure like the following:

Subject Event1

Observer1

Observer2

Event2

Observer1

Observer3

3204/10/23

Page 33: Observer and Decorator Pattern

Subject (Current Implementation)

3304/10/23

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?

Page 34: Observer and Decorator Pattern

Subject/SubjectEvent

3404/10/23

This class represents a specific event of the Subject.

Page 35: Observer and Decorator Pattern

SubjectEvent

3504/10/23

Now the SubjectEvent, not Subject, contains a reference to all of the Observers who are interested in being notified.

Page 36: Observer and Decorator Pattern

Subject/SubjectEvent

3604/10/23

The constructor of WeatherData takes a SubjectEvent as parameter.

Page 37: Observer and Decorator Pattern

WeatherDatapublic class WeatherData {

private SubjectEvent subEvent;

public WeatherData(SubjectEvent subEvent) {

this.subEvent = subEvent;

}

public void SetMeasurements(…)

{

this.temperature = temperature;

this.humidity = humidity;

this.pressure = pressure;

this.subEvent.NotifyObserver(this);

}

}

3704/10/23

Page 38: Observer and Decorator Pattern

SubjectEvent + Observers

In our prior design, what information did the Subject pass on to the Observers?

In this design, should the SubjectEvent pass the same information to the Observers?

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. So, what does the SubjectEvent also need to tell the Observers who

are listening to it?

3804/10/23

Page 39: Observer and Decorator Pattern

SubjectEvent

3904/10/23

Added name parameter to the constructor and storing it in eventName Field.

Page 40: Observer and Decorator Pattern

SubjectEvent

public class SubjectEvent {

private List<Observer> observers;

private string eventName;

public SubjectEvent(string name) {

observers = new List<Observer>();

eventName = name;

}

public void NotifyObserver(object subject) {

foreach (Observer observer in observers)

observer.Update(subject, eventName);

}

}

4004/10/23

Cheating

Page 41: Observer and Decorator Pattern

Observer

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?

What should the signature of the Update() function look like?

4104/10/23

Page 42: Observer and Decorator Pattern

Observer

public abstract class Observer {

public Observer(SubjectEvent subEvent) {

subEvent.RegisterObserver(this);

}

public abstract void Update(object data,

string eventName);

private Observer() { }

}

4204/10/23

Page 43: Observer and Decorator Pattern

CurrentConditionsDisplay

public override void Update(object data, string name) {

if (data is WeatherData) {

WeatherData weather = (WeatherData)data;

if (name.Equals("WeatherChanged"))

{

this.temperature = weather.getTemp();

this.humidity = weather.getHumidity();

this.pressure = weather.getPressure();

}

}

}

}

4304/10/23

Page 44: Observer and Decorator Pattern

Big Picture

4404/10/23

Page 45: Observer and Decorator Pattern

Client Code

//Create SubjectEvent..with specific event name

SubjectEvent event1 = new SubjectEvent("WeatherChanged");

//Create Observers for that event

CurrentConditionsDisplay observer1 = new CurrentConditionsDisplay(event1);

ForcastDisplay observer2 = new ForcastDisplay(event1);

//Create Subject (and pass in reference to the event)

WeatherData subject = new WeatherData(event1);

4504/10/23

Page 46: Observer and Decorator Pattern

Not done yet..

WeatherData just contains one event. Now we want to add a second event.

public class WeatherData {

SubjectEvent weatherEvent;

SubjectEvent disasterEvent;

public WeatherData(SubjectEvent weatherEvent, SubjectEvent disasterEvent) {

this.weatherEvent = weatherEvent;

this.disasterEvent = disasterEvent;

}

}

4604/10/23

Page 47: Observer and Decorator Pattern

WeatherData (cont)

public void WeatherMeasurementsChanged()

{

this.weatherEvent.NotifyObserver(this);

}

public void DisasterProbabilityChanged()

{

this.disasterEvent.NotifyObserver(this);

}

4704/10/23

Page 48: Observer and Decorator Pattern

ConcreteObserver

public override void Update(object data, string name) {

if (data is WeatherData)

{

WeatherData weather = (WeatherData)data;

if (name.Equals("WeatherChanged"))

{ //do weather stuff }

else if (name.Equals("DisasterComing"))

{

this.hurricaneProbability = weather.getHurricaneProb();

this.tornadoProbability = weather.getTornadoProb();

}

}

}

4804/10/23

Page 49: Observer and Decorator Pattern

Client Code

//Create Observers

CurrentConditionsDisplay observer1 = new CurrentConditionsDisplay();

ForcastDisplay observer2 = new ForcastDisplay();

//Create SubjectEvents

SubjectEvent se1 = new SubjectEvent("WeatherChanged");

se1.RegisterObserver(observer1);

se1.RegisterObserver(observer2);

SubjectEvent se2 = new SubjectEvent("DisasterComing");

se2.RegisterObserver(observer2);

//Create Subject

WeatherData wd = new WeatherData(se1, se2)

4904/10/23

Page 50: Observer and Decorator Pattern

Other Problems Arise.. 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?

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.

5004/10/23

Page 51: Observer and Decorator Pattern

Change Manager

Both of these problems can be solved with another objected called the ChangeManager.

This object is an example of Mediator Pattern 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.”

It can handle complex update strategies.

It can also be a Singleton!

5104/10/23

Page 52: Observer and Decorator Pattern

Features of the Change Manager

Contains a mapping of Subject-to-Observers.

Provides an interface for registering Subject to Observers.

Eliminates the need for Subject to maintain references to its Observers (and vica versa).

Defines a specific update strategy.

5204/10/23

Page 53: Observer and Decorator Pattern

Addressing Problem #2

ChangeManager can store the relationship between each Subject to Observers. For example:

Subject : WeatherData (DC) Observer(s): CurrentConditions, ForcastDisplay

Subject : WeatherData (VA) Observer(s): CurrentConditions

Subject : WeatherData (MD) Observer(s): CurrentConditions, StatisticsDisplay

5304/10/23

Page 54: Observer and Decorator Pattern

Addressing Problem #2 (cont)

When WeatherData(DC) has an internal update, it sends a message to ChangeManager to notify observers.

The ChangeManager contains an internal state that indicates if all three WeatherData objects have indicated a recent change.

If ChangeManager determines that all three WeatherData objects have indicted a change, it sends a message to each Observer associated with each Subject.

5404/10/23

Page 55: Observer and Decorator Pattern

Using Event Infrastructure

All of these examples have been using the Classical Definition of the Observer pattern.

There are language specific features of C# and Java that can be used to make this pattern much simpler to use.

Using the Event infrastructure: RegisterObserver Register Event with Handler RemoveObserver Unregister Event with Handler NotifyObserver Raise Event Special data about the Event can be passed as Event argument.

5504/10/23

Page 56: Observer and Decorator Pattern

Real World Examples

Problem #1 Search screen that lists documents with a Status per document From the screen, user can open one or more documents. When a document is opened, the status is changed. User closes document, the search screen still displays the old

status.

Who are the Observers?

Who are the Subjects?

5604/10/23

Page 57: Observer and Decorator Pattern

Solution #1Search Screen = Observer (Just one)

Each opened document = Subject

So we have one Observer with multiple Subjects.

When a document is opened, the Search screen (Observer) must register itself with the Document (Subject).

Subject must broadcast a notify message when its Status state changes.

Observer, upon receiving the message, can update its state and display the updated status.

When Subject closes, the Observer must unregister itself with the Subject. (The Subject needs to tell the Observer that it is closing) 57

Page 58: Observer and Decorator Pattern

Problem #2

Document structure that contains Parent and Child nodes.

When a Parent Node changes, all of the Child Nodes need to be re-validated.

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.

Who are Observers? Subjects?

5804/10/23

Page 59: Observer and Decorator Pattern

Solution #2 Observers – All Child Nodes for a single Parent Subject – Single Parent Node So multiple Observers with one Subject.

All Observers must register themselves with a data change event for the Subject.

When the Subject changes it state, a data change notification is sent.

Each Subject re-validates itself.

Also: See Composite Pattern. 59

Page 60: Observer and Decorator Pattern

Problem #3 A Business Object is composed of multiple Properties.

Each property has one or more validation rules associated with it.

When a Business Object is loaded, each validation rule on each property is executed.

6004/10/23

Page 61: Observer and Decorator Pattern

Problem #3 (Cont)

Property A Rule #1: Must have a value Rule #2: Must be a valid look-up value in the database

(Precondition: Must have a value) Rule #3: Must contain a valid combination with Property B and

C. (Preconditions: Must have a value; must be valid in db)

Problem: These three rules have no relationship with each other…yet

there seems to be a logical relationship. Rules 2 and 3 perform duplication of logic in the pre-conditions. There is no reason to run the expensive precondition logic of

Rule #3 if Rule #2 is not valid (yet we do it anyway).

6104/10/23

Page 62: Observer and Decorator Pattern

Solution #3 Change Manager. Let’s look at the internal mapping:

Mapping 1: Subject: Rule #1 Observers: Rule #2, Rule #3

Mapping 2: Subject: Rule #2 Observers: Rule #3

Note: Rule #2 is both a Subject and an Observer.

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.

62

Page 63: Observer and Decorator Pattern

Solution #3 This can get complex very quickly.

This really may not be a practical solution at all.

If used, would focus on the rules that are the most expensive. (Performance Testing can help identify).

6304/10/23

Page 64: Observer and Decorator Pattern

Lab (Introduction to Decorator)

We have a simple class for logging message and one implementation.

public class DefaultLogger {

public virtual void Log(string file, string msg)

{

//Open File

//Write msg to file

}

}

6404/10/23

Page 65: Observer and Decorator Pattern

LabA new requirement states that we need to extend the

DefaultLogger to encrypt messages before we log. This can be done simply with inheritance:

public class EncryptedLogger : DefaultLogger { public override void Log(string file, string msg)

{

//Encrypt Message

//Call base functionality

base.Log(file, msg);

}

}

6504/10/23

Page 66: Observer and Decorator Pattern

Lab

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:

public class CompressLogger : EncryptedLogger { public override void Log(string file, string msg)

{

//Compress Message

//Call base functionality, which Encrypts and

//then writes basic functionlity

base.Log(file, msg);

}

}66

Page 67: Observer and Decorator Pattern

Lab

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.

Using inheritance, what class would we need to inherit from? What problem do we have?

6704/10/23

Page 68: Observer and Decorator Pattern

Problem

Inheritance statically defined an order of enhancing behavior.

We ran into an issue when we wanted more flexibility in adding behavior.

Using a Decorator, we can add (and remove) behavior at will!

6804/10/23

Page 69: Observer and Decorator Pattern

Solution

public abstract class LoggerDecorator : DefaultLogger {

public override void Log(string file, string msg) {

base.Log(file, msg);

}

}

6904/10/23

This is our Decorator class. In this example, it is extending the class that we want to enhance with additional functionality.

Page 70: Observer and Decorator Pattern

EncryptedLogger

public class EncryptedLogger : LoggerDecorator {

DefaultLogger dLogger;

public EncryptedLogger(DefaultLogger logger)

{

this.dLogger = logger;

}

public override void Log(string file, string msg)

{

//Do encryprted functionality

string encryptedMsg = msg;

Console.WriteLine("Encrpytion");

dLogger.Log(file, encryptedMsg);

}

}

7004/10/23

This is the object we want to extend

Page 71: Observer and Decorator Pattern

CompressionLogger public class CompressedLogger : LoggerDecorator {

DefaultLogger dLogger;

public CompressedLogger(DefaultLogger logger)

{

this.dLogger = logger;

}

public override void Log(string file, string msg)

{

//Do compressed logic

string compressMsg = msg;

Console.WriteLine("Compression");

dLogger.Log(file, compressMsg);

}

}

7104/10/23

Page 72: Observer and Decorator Pattern

Client Code

//Simple log

DefaultLogger logger1 = new DefaultLogger();

logger1.Log("log1.txt", "here is a message");

//Add encryption

EncryptedLogger eLogger = new EncryptedLogger(logger1);

eLogger.Log("log2.txt", "encrypt this!");

//Add compression

CompressedLogger cLogger = new CompressedLogger(eLogger);

Logger.Log("log3.txt", "compress this");

7204/10/23

Page 73: Observer and Decorator Pattern

Decorator

GoF Intent: “Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.”

7304/10/23

Page 74: Observer and Decorator Pattern

Things to Note

Composition, not Inheritance, was used to extend behavior.

No changes were made to the original class (DefaultLogger).

We could have provided a GUI so that the end user could specify the behaviors to use.

7404/10/23

Page 75: Observer and Decorator Pattern

Comparison to Other Patterns

Strategy Good to use when we need to change the “guts” of an object. 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.

Adapter Just changes the interface of an object. A decorator will enhance behavior of an object.

7504/10/23