 |
Define a one-to-many dependency between objects so that when one
object changes state, all its dependents are notified and updated automatically.
Frequency of use: high
|
|
 |
The classes and/or objects participating in this pattern are:
- Subject (Stock)
- knows its observers. Any number of
Observer objects may observe a subject
- provides an interface for attaching and detaching Observer objects.
- ConcreteSubject (IBM)
- stores state of interest to
ConcreteObserver
- sends a notification to its observers when its state changes
- Observer (IInvestor)
- defines an updating interface for objects that should be notified of changes in a subject.
- ConcreteObserver (Investor)
- maintains a reference to a
ConcreteSubject object
- stores state that should stay
consistent with the subject's
- implements the Observer updating interface to keep its state consistent
with the subject's
This structural code demonstrates the Observer pattern in which registered objects
are notified of and updated with a state change.
Show code
|
// Observer pattern -- Structural example
|
|
using System;
using System.Collections;
namespace DoFactory.GangOfFour.Observer.Structural
{
// MainApp test application
class MainApp
{
static void Main()
{
// Configure Observer pattern
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s,"X"));
s.Attach(new ConcreteObserver(s,"Y"));
s.Attach(new ConcreteObserver(s,"Z"));
// Change subject and notify observers
s.SubjectState = "ABC";
s.Notify();
// Wait for user
Console.Read();
}
}
// "Subject"
abstract class Subject
{
private ArrayList observers = new ArrayList();
public void Attach(Observer observer)
{
observers.Add(observer);
}
public void Detach(Observer observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
// "ConcreteSubject"
class ConcreteSubject : Subject
{
private string subjectState;
// Property
public string SubjectState
{
get{ return subjectState; }
set{ subjectState = value; }
}
}
// "Observer"
abstract class Observer
{
public abstract void Update();
}
// "ConcreteObserver"
class ConcreteObserver : Observer
{
private string name;
private string observerState;
private ConcreteSubject subject;
// Constructor
public ConcreteObserver(
ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("Observer {0}'s new state is {1}",
name, observerState);
}
// Property
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
}
|
Output
Observer X's new state is ABC
Observer Y's new state is ABC
Observer Z's new state is ABC
|
This real-world code demonstrates the Observer pattern in which registered investors
are notified every time a stock changes value.
Show code
|
// Observer pattern -- Real World example
|
|
using System;
using System.Collections;
namespace DoFactory.GangOfFour.Observer.RealWorld
{
// MainApp test application
class MainApp
{
static void Main()
{
// Create investors
Investor s = new Investor("Sorros");
Investor b = new Investor("Berkshire");
// Create IBM stock and attach investors
IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(s);
ibm.Attach(b);
// Change price, which notifies investors
ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
// Wait for user
Console.Read();
}
}
// "Subject"
abstract class Stock
{
protected string symbol;
protected double price;
private ArrayList investors = new ArrayList();
// Constructor
public Stock(string symbol, double price)
{
this.symbol = symbol;
this.price = price;
}
public void Attach(Investor investor)
{
investors.Add(investor);
}
public void Detach(Investor investor)
{
investors.Remove(investor);
}
public void Notify()
{
foreach (Investor investor in investors)
{
investor.Update(this);
}
Console.WriteLine("");
}
// Properties
public double Price
{
get{ return price; }
set
{
price = value;
Notify();
}
}
public string Symbol
{
get{ return symbol; }
set{ symbol = value; }
}
}
// "ConcreteSubject"
class IBM : Stock
{
// Constructor
public IBM(string symbol, double price)
: base(symbol, price)
{
}
}
// "Observer"
interface IInvestor
{
void Update(Stock stock);
}
// "ConcreteObserver"
class Investor : IInvestor
{
private string name;
private Stock stock;
// Constructor
public Investor(string name)
{
this.name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("Notified {0} of {1}'s " +
"change to {2:C}", name, stock.Symbol, stock.Price);
}
// Property
public Stock Stock
{
get{ return stock; }
set{ stock = value; }
}
}
}
|
Output
Notified Sorros of IBM's change to $120.10
Notified Berkshire of IBM's change to $120.10
Notified Sorros of IBM's change to $121.00
Notified Berkshire of IBM's change to $121.00
Notified Sorros of IBM's change to $120.50
Notified Berkshire of IBM's change to $120.50
Notified Sorros of IBM's change to $120.75
Notified Berkshire of IBM's change to $120.75
|
This .NET optimized code demonstrates the
same real-world situation as above but uses modern, built-in .NET features.
Show code
|
// Observer pattern -- .NET optimized
|
See our Singleton page for a .NET optimized code sample.
|
|
|