Oliver Haase
Design Patterns
Observer
1
Design Patterns Observer Oliver Haase 1 Description Object based - - PowerPoint PPT Presentation
Design Patterns Observer Oliver Haase 1 Description Object based behavioral pattern Purpose : Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated
Oliver Haase
1
2
dependents are notified and updated automatically.
Model View 1 View 2 View 3 Observer Subject, Observable notify get update
3
more general, related to event listeners
update() Observer concreteSubject.get() attach(Observer) detach(Observer) notify() Subject update() ConcreteObserver
get() set(s) state ConcreteSubject concreteSubject state = s notify() return state for each o in observers
4
and detaching observers
defines call-back operation to get notified uses concrete subject’s get
updated state
Use the Observer pattern when
increase the chance to reuse them independently.
without knowing them.
5
to its internal state happens.
subject state by using the get() method.
ConcreteObserver uses this information to change its own
internal state.
6
and reused individually.
registered.
interested in
specific state change of the subject.
7
information → Pull Model
8
Pull Model Push Model signature of notify
number of
unnecessarily exchanged state information independent of subject’s state fields subject to modification if subject’s state fields are changed higher lower fewer more
9
Call of notifyObservers without prior call of setChanged has no effect!
update(Observable, Object) <<interface>> Observer + addObserver(Observer) + deleteObserver(Observer) + notifyObservers() # setChanged() Observable update(Observable, Object) MyObserver
getState() setState(s) state MyObservable state = s setChanged() notifyObservers()
10
→ implementation inheritance, and → interface inheritance ⇒ SmartAdapter!
→ No, because setChanged is protected.
11
update(Observable, Object) <<interface>> Observer + addObserver(Observer) + deleteObserver(Observer) + notifyObservers() # setChanged() Observable update(Observable, Object) MyObserver
getState() setState(s) state delegate MyObservable MySuper state = s delegate.setChanged() delegate.notify() + setChanged() + getState() + setState(s) delegate SmartObservableAdapter delegate.setState(s) return delegate.getState() super.setChanged()
Naive implementation of attach(), detach(), and notify()
12 public final class NaiveSubject { private final Vector<Observer> observers; ... public final void attach(Observer o) {
} public final void detach(Observer o) {
} public final void notifyObservers() { for(Observer o : observers) {
} } }
ConcurrentModificationException if a thread adds or
removes an observer while another notifies the observers.
does it)
13
constructor!
14
→ Otherwise the observer’s this reference escapes before the subject is fully constructed. Reminder: In general, do not register a listener at an event source within listener’s constructor!
15
MVC architectural pattern almost always uses Observer pattern.
16
17
hard to understand.
aware of the mediator.
18
keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Mediator Colleague ConcreteMediator ConcreteColleague2 ConcreteColleague1 mediator
19
and not with the other colleague-objects
behavior by coordinating the colleague-objects
colleague-objects defines an interface for the interaction with colleague-objects
Use the Mediator pattern when
but the dependencies are unstructured and hard to understand.
many other objects.
be customizable without a lot of subclassing
20
21
colleague-classes know their broker.
Observer pattern.
pattern.
22
23
24
violating encapsulation and thus providing a mean for restoring the object into initial state when needed.
25
return new Memento(state) CareTaker getState() setState(state) state Memento createMemento() setMemento(Memento m) state Originator memento state = m.getState()
26
capturing the originator’s internal state.
its previous state. The memento is opaque to the caretaker, and the caretaker must not operate on it.
27
:Caretaker :Originator aMemento:Memento
createMemento() new Memento() setState() setMemento(aMemento) getState()
Use the Memento pattern if
restored later on, and if
encapsulation.
28
Originator can access the Memento’s state.
29
→ Make Memento an inner class of Originator
30 public final class Originator { private int state; public Memento createMemento() { return new Memento(state); } public void setMemento(Memento memento) { state = memento.getState(); } public static final class Memento { private final int state; private Memento(int state) { this.state = state; } private int getState() { return state; } } }
private method of static inner class can be called by outer class
for undoable operations.
iteration.
31
32
33
algorithm vary independent of clients that use it.
34
@Immutable public final class OriginalAIOpponent { private final Level skill; public OriginalAIOpponent(Level skill) { this.skill = skill; } public void repelMove(int posX, int posY) { switch (skill) { case LOUSY: // do something break; case ... } } public void printCoolSlogan() { switch (skill) { case LOUSY: // print something break; case ... } } } public enum Level { LOUSY, STRONG; }
35
Define strategy interfaces:
36 public interface RepelStrategy { void repelMove(int posX, int posY); } public interface SloganStrategy { void printCoolSlogan(); }
Sample implementation:
public class LousySloganStrategy implements SloganStrategy { @Override public void printCoolSlogan() { System.out.println("Please don't hurt me!"); } }
37 public class AIOpponent { private final RepelStrategy repelStrategy; private final SloganStrategy sloganStrategy; public AIOpponent(RepelStrategy repelStrategy, SloganStrategy sloganStrategy) { this.repelStrategy = repelStrategy; this.sloganStrategy = sloganStrategy; } public void repelMove(int posX, int posY) { repelStrategy.repelMove(posX, posY); } public void printCoolSlogan() { sloganStrategy.printCoolSlogan(); } } AIOpponent o = new AIOpponent( new LousyRepelStrategy(), new LousySloganStrategy());
38
printCoolSlogan() <<interface>> SloganStrategy sloganStrategy.printCoolSlogan() printCoolSlogan() LousySloganStrategy ContextInterface() AIOpponent printCoolSlogan() StrongSloganStrategy sloganStrategy
AlgorithmInterface() Strategy strategy.AlgorithmInterface() AlgorithmInterface() ConcreteStrategyA ContextInterface() Context AlgorithmInterface() ConcreteStrategyB strategy
39
access its data implements the algorithm using the Strategy interface interface common to all supported algorithms
Use the Strategy pattern when
provide a way to configure a class with one of many behaviors.
statements).
40
to the strategy method.
method.
41
42
(AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy,
DiscardPolicy)
JComponent
43
44