Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
The Observer Pattern
CSCI 3132 Summer 2011 1
Seven Sins of Design
• Rigidity – make it hard to change • Fragility – make it easy to break
• Immobility – make it hard to reuse
• Viscosity – make it hard to do the right thing
• Needless Complexity – over design
• Needless RepeAAon – error prone
• Not doing any 2
The Rules • Apply Common Sense • Don’t get too dogmaAc / religious
• Every decision is a tradeoff
• All other principles are just that – Guidelines – “best pracAces” – Consider carefully if you should violate them -‐ but, know you can.
3
Open Closed Principle
• SoRware enAAes ( Classes, Modules, Methods, etc. ) should be open for extension, but closed for modificaAon.
• Also Known As Protected VariaAon • QuesAon: This principle is applied to which of the design paZerns we have learned so far?
4
Single Responsibility Principle
• A Class should have one reason to change – A Responsibility is a reasons to change
• Can be tricky to get granularity right • Single Responsibility = increased cohesion • Not following results in needless dependencies
– More reasons to change. – Rigidity, Immobility
• QuesAon: This principle is applied to which of the design paZerns we have learned so far?
5
Consider the Following ApplicaAon
Humidity
Temperature
Pressure
Weather StaAon
Weather Data Object
Three Displays
6
What’s Given
• The WeatherData class has geZer methods that obtain measurement values from temperature, humidity and pressure.
• The class has a measurementsChanged() method that updates the three values.
• Three displays must be implemented: current condiAons, staAsAcs and forecast display.
• System must be expandable – other display elements maybe added or removed.
7
A First AZempt class WeatherData{!public: ! ! void measurementChanged(){!! ! float temp = getTemperature();!! ! float humidity = getHumidity();!! ! float pressure = getPressure();!! ! currentConditionsDisplay.update(temp,humidity,
!! ! ! ! ! pressure)!! ! ! statisticsDisplay.update(temp,humidity,pressure)!! !! forecastDisplay.update(temp,humidity,pressure)! }!! //other WeatherData methods here!}; !
8
The Observer PaZern “Observed”
Subject Object
int 2
Dog Object Registers Observers
Dog Object
Cat Object
Duck Object
Subject Broadcasts
2
Cat Object Registers Duck Object Registers Subject is updated
int 8
Cat object de-‐registers
Cat Object
Subject Broadcasts
8
8
Other examples: “publish and subscription” services; eBay
9
Handling the addiAon of new customers:
• Sending a welcome leZer • Verify the customer’s address with the post office
Another Example
10
Customer: When a customer is added, this object will make the calls to the other objects to have the corresponding acAons take place
WelcomeLeZer: Creates welcome leZers for customers that let them know they were added to the system.
AddrVerificaAon: This object will verify the address of any customer that asks it to
A First Try
11
We do not want to change the broadcasAng object every Ame there is a change to the set of objects listening to the broadcast.
We want to decouple the noAfy-‐ers (subject) and the noAfy-‐ees(observer).
Two things vary • Different kinds of objects – ones that need to be noAfied
of a change in state.
• Different interfaces – Each object that requires noAficaAon may have a different interface.
Decoupling
12
All observers must have the same interface. All observers must register themselves. This makes them
responsible for knowing what they are watching for. We must add two methods to the subject. • attach(Observer) adds the given observer to its
list of observers. • detatch(Observer) removes the given observer
from its list of observers.
The observer must implement a method called update. The subject implements the notify method that goes
through its list of Observers and calls this update method for each of them.
A BeZer SoluAon
13
The Class Diagram
14
class Customer{!public:! void attach( Observer *myObserver);! void detach( Observer *myObserver);! void notify();!private:! vector<Observer*> myObs;!};!void Customer::attach( Observer *myObserver)!{! myObs.push_back( myObserver);!}!
Example (Cont’d)
15
void Customer::detach( Observer *myObserver){! for (int i= 0; i< myObs.size(); i++){! if (myObs[i]== myObserver){! myObs.erase(myObs.begin()+i);! return;! }! }!}!void Customer::notify(){! for (int i= 0; i< myObs.size(); i++){! myObs[i]->update(this);! }!}!
Example (Cont’d)
16
DefiniAon
• The observer paZern implements a one-‐to-‐many relaAonship between a set of objects.
• A single object changes state and updates the objects (dependants) that are affected by the change.
• The object that changes state is called the subject and the other objects are the observers.
17
Loose Coupling
• Subjects and observers are loosely coupled. • The subject only knows the observer interface and not its implementaAon.
• Observers can be added and removed at any Ame. • In adding new observers the subject does not need to be modified.
• Subjects and observers can be reused independently.
• Changes to the subject or observer will not affect the other.
18
Design Principle
• Strive for loosely coupled designs between objects that interact.
• Loosely coupled designs allow us to build flexible object-‐oriented systems.
• These systems can handle change because they minimize the interdependency between objects.
19
Observer Applicability
• Use the Observer paZern in any of the following situaAons – When an abstracAon has two aspects, one dependent on the other. EncapsulaAng these aspects in separate objects lets you vary and reuse them independtly.
– When a change to one object requires changing others, and you do not know how many objects need to be changed.
– When an object should be able to noAfy other objects without making assumpAons about who these objects are. 20
Observer ParAcipants
• Subject – Knows its observers. Any numberof Observer objects may observe a subject.
– Provides an interface for aZaching and detaching Observer Objects.
• Observer – Defines an updaAng interface for objects that should be noAfied of changes in a subject
21
Observer ParAcipants • ConcreteSubject
– Stores a state of interest to ConcreteObserver objects.
– Sends a noAficaAon to its observers when its state changes.
• ConcreteObserver – Maintains a reference to a ConcreteSubject object
– Stores state that should stay consistent with the subject state.
– Implements the Observer updaAng interface to keep its state consistent with the subject state. 22
Weather StaAon Class Diagram
23
The Observer PaZern: Key Features
Intent: Define a one-‐to-‐many dependency between objects so that when one object changes state, all its dependents are noAfied and updated automaAcally.
Problem: You need to noAfy a varying list of objects that an event has occurred.
Solu.on: Observers delegate the responsibility for monitoring for an event to a central object: The subject.
24
The Observer PaZern: Key Features
Implementa.on: Have objects (Observers) that want to know when an event happen aZach themselves to another object (Subject) that is watching for the event to occur or that triggers the event itself.
When the event occurs, the Subject tells the Observers that it has occurred.
The Adapter paZern is someAmes needed to be able to implement the Observer interface for all the Observer-‐type objects.
25
Observer PaZern: Class Diagram
26
Observer Sequence Diagram
ConcreteSubject Object
ConcreteObserver ObjectA
ConcreteObserver ObjectB
Notify()
SetState()
Update()
GetState()
Update() GetState()
27
Observer Consequences
• Abstract coupling between Subject and Object – All a subject knows is that it has a list of observers, each conforming to the simple interface of the abstract Observer class. The subject does not know the concrete class of any observer.
• Support for broadcast communicaAon – Unlike and ordinary request, the noAficaAon that a subject sends need not specify its receiver. The noAficaAon is broadcast automaAcally to all interested objects that subscribed to it.
28
Observer ImplementaAon • How to noAfy -‐ Approach 1 void ConcreteSubject::setstate(int newstate) { state_=newstate; notify(); // notify all observers that // state
has changed }
Subject s1; subject.setstate(6); // automatic call to notify Subject.setstate(5);
29
Observer ImplementaAon
• How to noAfy -‐ Approach 2 void ConcreteSubject::setstate(int newstate) { state_=newstate; }
Subject s1; subject.setstate(6); subject.setstate(5); Subject.notify(); // explicit call to notify
30
Observer ImplementaAon
• the Push model and the Pull model – ImplementaAons of the Observer paZern oRen have the subject broadcast addiAonal informaAon about the change. The subject passes this informaAon as an argument to Update.
– Push model: the subject sends obervers detailed informaAon about the change
– Pull model: the subject sends only a minimal noAficaAon and observers ask for details explicitly
31
Observer ImplementaAon
What happens when we add new observers?
Imagine adding the ability to send a leZer with coupons to customers located within 20 miles of one of the company’s “Brick and Mortar” stores.
32
Observer ImplementaAon If the class we want to add already exists and we can not modify it,
then we can adapt it as shown below:
33