Oliver Haase
Design Patterns
Observer
Description
‣
Object based behavioral pattern‣
Purpose: Define a one-to-many dependency between objects so that when one object changes state, all itsdependents are notified and updated automatically.
‣
Also Known As: Publish-SubscribeModel
View 1
View 2
View 3 Observer Subject,
Observable
notify
get update
Motivating Example
‣
keep consistency between decoupled objects‣
often used in the context of the MVC architectural pattern, more general, related to eventlisteners
‣
helps build a layered architectureupdate() Observer
concreteSubject.get() attach(Observer)
detach(Observer) notify()
Subject
update()
ConcreteObserver observers
get() set(s) state
ConcreteSubject concreteSubject
state = s notify()
return state
for each o in observers o.update()
General Structure
‣knows its observers
‣provides interface for attaching and detaching observers
defines call-back operation to get notified
uses concrete subject’s get operations to pull
updated state
Applicability
Use the Observer pattern when
‣
the abstraction has two aspects where one depends on the other. Encapsulating these aspects in separate objects will increase the chance to reuse them independently.‣
the subject doesn't know in advance how many observer objects it will have.‣
the subject should be able to notify its observer objects without knowing them.Interactions
‣ ConcreteSubject notifies its observers whenever a change to its internal state happens.
‣
After a ConcreteObserver gets notified, it may query the subject state by using the get() method.ConcreteObserver uses this information to change its own internal state.
Pros & Cons
‣
Pros:•
Decoupling of subject and observer, each can be extended and reused individually.•
Dynamic addition and removal of observers at runtime.•
Subject broadcasts notification automatically to all interested objects, no matter how many or which kind of observers are registered.‣
Cons:•
May result in many notifications the observers are not interested in•
Potentially difficult for the observers to figure out the specific state change of the subject.Push vs. Pull Model
‣
In its purest form, notification does not carry updated state information → Pull Model‣
Variant: notification contains updated state → Push ModelPull Model Push Model
signature of notify operation
number of operation calls
unnecessarily exchanged state
information
independent of subject’s state
fields subject to modification if subject’s state fields are changed
higher lower
fewer more
Observer in Java
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
observers
getState() setState(s) state
MyObservable
state = s
setChanged() notifyObservers()
Observer in Java
‣ Observable is a class.
‣
What if our observable subject already has a super-class?‣
What aspects of inheritance are needed?→ implementation inheritance, and
→ interface inheritance
SmartAdapter!
‣
Can class Observable be delegated to?→ No, because setChanged is protected.
‣
Adapter & Delegation (see Implementation Reuse patterns)Observer in Java: SmartAdapter
update(Observable, Object)
<<interface>>
Observer + addObserver(Observer)
+ deleteObserver(Observer) + notifyObservers()
# setChanged()
Observable
update(Observable, Object) MyObserver
observers
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()
Observer and Concurrency
Naive implementation of attach(), detach(), and notify()
public final class NaiveSubject {
private final Vector<Observer> observers;
...
public final void attach(Observer o) { observers.addElement(o);
}
public final void detach(Observer o) { observers.removeElement(o);
}
public final void notifyObservers() { for(Observer o : observers) {
o.update();
}
Observer and Concurrency
‣ Vector is thread-safe, but NaiveSubject is not.
‣ NaiveSubject will throw
ConcurrentModificationException if a thread adds or removes an observer while another notifies the observers.
‣
Possible solutions:•
Java Monitor Pattern (risky because of alien method call)•
Use CopyOnWriteArrayList•
Copy vector before iteration (this is how JDK Observabledoes it)
Observer and Concurrency
‣
Do not attach observer to subject inside observer’s constructor!→ 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!
Relationship with other Patterns
MVC architectural pattern almost always uses Observer pattern.
Mediator
Motivation
‣
Complex systems often require that the participating objects know each other.‣
This might end up in a nontransparent situation which is hard to understand.‣
The Mediator now supervises this communication.‣
It knows all the objects taking part and the objects are only aware of the mediator.Description
‣
Object based behavioral pattern‣
Purpose: Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling bykeeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
‣
Also Known As: BrokerMediator Colleague
ConcreteMediator ConcreteColleague1 ConcreteColleague2 mediator
General Structure
‣Each colleague-class knows its broker-class
‣Each colleague-object works with its broker and not with the other colleague-objects
‣implements the general behavior by coordinating the colleague-objects
‣knows and manages its colleague-objects
defines an interface for the interaction with
colleague-objects
Applicability
Use the Mediator pattern when
‣
there are many objects that have to work with each other, but the dependencies are unstructured and hard tounderstand.
‣
reusability of object is hard, because it has dependencies to many other objects.‣
a behavior that's distributed between several classes should be customizable without a lot of subclassingPros & Cons
‣
Pro:•
Limits subclassing•
Decoupled colleague-objects•
n:n-relations converted to 1:n-relations•
Abstracts how the colleague-objects work with each other•
Centralized control‣
Con:•
Broker class might turn into a hard to maintain monolithRelationship with other Patterns
‣
Facade: Subsystem-classes don‘t know about the facade;colleague-classes know their broker.
‣
Colleague objects can notify the broker using the Observer pattern.‣
If the Mediator alters message then it is an Adapter pattern.Memento
Description
‣
Object based behavioral pattern‣
Purpose: Capture the internal state of an object without violating encapsulation and thus providing a mean forrestoring the object into initial state when needed.
‣
Also Known As: TokenDescription
‣
Used for: Undo functionality‣
A Memento is an object which saves a snapshot of an originator’s internal state.‣
Only the originator has access to the state of the memento object.return new Memento(state) CareTaker
getState()
setState(state) state
Memento
createMemento()
setMemento(Memento m) state
Originator memento
state = m.getState()
General Structure
‣Creates a memento object
capturing the originator’s internal state.
‣Use the memento object to restore its previous state.
The memento is opaque to the caretaker, and the caretaker
must not operate on it.
‣Saves the state information
‣Full access only from the originator
Interactions
:Caretaker :Originator aMemento:Memento
createMemento() new Memento() setState()
setMemento(aMemento)
getState()
Applicability
Use the Memento pattern if
‣
an object's state must be captured so that it can be restored later on, and if‣
explicitly passing the state of the object would violate encapsulation.Consequences
‣
Preserves encapsulation.‣ CareTaker simplifies originator code.
‣
Using the memento pattern can be expensive.‣
In some languages it is hard to ensure that only theOriginator can access the Memento’s state.
•
How can we ensure this in Java?→ Make Memento an inner class of Originator
Ensure encapsulation in Java
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
Relationship with other Patterns
‣
Command objects can use mementos to maintain state for undoable operations.‣
Iterator can use memento objects to save state of iteration.Strategy
Description
‣
Object based behavioral pattern‣
Purpose: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets thealgorithm vary independent of clients that use it.
‣
Also Known As: PolicyMotivating Example
@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 public enum Level {
LOUSY, STRONG;
}
Motivating Example
‣
Options if we need to add a new skill level?•
add case to Opponent class (easy to forget an occurrence)•
create subclass of Opponent•
outsource different behaviorMotivating Example
Define strategy interfaces:
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!");
} }
Motivating Example
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());
Sample Structure
printCoolSlogan()
<<interface>>
SloganStrategy
sloganStrategy.printCoolSlogan()
printCoolSlogan()
LousySloganStrategy ContextInterface()
AIOpponent
printCoolSlogan()
StrongSloganStrategy sloganStrategy
AlgorithmInterface() Strategy
strategy.AlgorithmInterface()
AlgorithmInterface() ConcreteStrategyA ContextInterface()
Context
AlgorithmInterface() ConcreteStrategyB strategy
General Structure
‣gets configured with ConcreteStrategy object
‣may define interface that lets Strategy access its data
implements the algorithm using the Strategy interface
interface common to all supported algorithms
Applicability
Use the Strategy pattern when
‣
many related classes differ only in their behavior. Strategies provide a way to configure a class with one of manybehaviors.
‣
need of different variants of algorithms.‣
an algorithm uses data that clients shouldn’t know about‣
A class defines many behaviors (use of multiple conditional statements).‣
Remark: be aware of switch-case-statements, they have a smellInteractions
‣
A context forwards requests from its clients to its strategy.‣
Data handover:•
A context may hand over all data required by the algorithm to the strategy method.•
The context can pass itself as an argument to Strategy method.Pros & Cons
‣
Pro:•
Re-usability of algorithms•
An alternative to sub-classing of the context class•
Choice of different implementations•
Elimination of conditional statements•
clean separation of different algorithms ➔ easier to test‣
Con:•
Clients must be aware of different strategies•
Communication overhead•
Increased number of objectsReal World Examples
‣ ThreadPoolExecutor gets RejectedExecutionHandler
object to decide strategy for tasks that cannot be executed (AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy,
DiscardPolicy)
‣
Java Comparator interface‣
Java AWT and Swing, e.g. paintBorder() method ofJComponent