Observer, Strategy, Decorator, Prototype,
description
Transcript of Observer, Strategy, Decorator, Prototype,
Observer, Strategy, Decorator, Prototype,
Observer Pattern
Dependence mechanism / publish-subscribe / event handler / constraints / broadcast
Let objects propagate information without depending on each other much.
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Observer Pattern
ObserverObserver
update:update:
SubjectSubject
addDependent: addDependent: removeDependent: removeDependent: changed:changed:
ValueHolderValueHoldervalue:value:valuevalue
TextViewTextView
update:update:
observer/observer/dependentdependent
modelmodel
Observer Pattern:
Registrationsubject addDependent: observer
Notificationself changed. self changed: #value
Updatedefine update: aSymbol
Notification
Object notifies dependents when information changes by sending itself a #changed message.
changed: anArg
self dependents
do: [:each | each update: anArg]
Problem
A man and dog are in the room. When the dog wants to go out, he barks. When the man hears the dog barking, he opens the door. When the dog wants to go out and the door is open, he leaves.
Basic classes
Dog
bark / move
Person
Door
open / close / isOpen
Object
addDependent:
changed:
update:
Collaborations
PersonDoor
openclose
Dog
bark listenwatch
Dynamic ModelRecord order of events, interaction between objects.Record order of events, interaction between objects.
DogDog PersonPerson DoorDoor
Sequence diagramSequence diagram
barkbarkopenopennotifynotify
go thru doorgo thru door
notifynotifycloseclose
registerregisterregisterregister
unregisterunregister
notifynotify
A Script
| person door dog |door := Door new close.dog := Dog new.dog door: door.person := Person new.person door: door; dog: dog.dog bark.
Dooropened <Boolean>
open
opened := true.
self changed: #open
Door
close
opened := false.
self changed: #close
isOpen
^opened
DogcurrentState :: #sleeping, #waiting, #outside
bark
currentState := #waiting.
self changed: #bark
door: aDoor
door := aDoor.
door addDependent: self
Dog
goOut
currentState := #outside.
door removeDependent: self.
self changed: #move
Dogupdate: aSymbol
(currentState == #waiting) & (aSymbol == #open)
ifTrue: [self goOut ]
Person
dog: aDog
dog := aDog.
dog addDependent: self
Person
update: aSymbol
aSymbol == #bark
ifTrue: [door open].
aSymbol == #move
ifTrue: [door close]
Watcher
instance variable: name <String>update: aSymbol
Transcript show: subjectName; show: ' '; show: aSymbol; cr
name: aStringname := aString
| person door dog |door := Door new close.door addDependent:
(Watcher new name: 'door').dog := Dog new.door addDependent: dog.dog addDependent:
(Watcher new name: 'Fido').person := Person new.person door: door; dog: dog.dog bark.
Improvements
Creating method
(have class method return initialized object)
Compose method
(Watcher on: door name: 'door')
(door watcherNamed: 'door')
Model and Memory Management
Dog allInstancesreports a lot of dogs! Garbage
collection doesn't help.Object uses a global dictionary to store
dependents. Subject must "release" its observers/dependents.
Make Dog a subclass of Model
Model uses an instance variable to store dependents. It does not have to release its observers.
Subclasses of Model cause less problems with garbage collection.
Class that has dependents should be subclass of Model.
If you are not using Model then after the script says
dog bark.
add the messages
dog release.
door release.
person release
Advantage of Observer Pattern
Easy to add new observers.
Coupling between observer and subject is abstract.
Disadvantage of Observer Pattern
Often hard to understand relationships between objects in system.
Sometimes inefficient.
Adding New Observer
Suppose room also has a bird, which is usually in a cage.
If bird is not in cage and door opens, bird flies out.
Bird
update: aSymbol
(aSymbol == #open) &
(self isCaged not)
ifTrue: [self flyOut]
Script must now create a bird and make it depend on the door.
Summary
Observer is an important patternUsed in a UI to make reusable componentsReduces coupling by increasing abstractionAbstraction makes programs easier to change, harder to understandOften requires a “script” to set up dependencies