A very common design pattern is the Observer pattern. Where do we see Observer patterns in our code? Events and delegates. Essentially Events are a slightly modified version of a delegate, and delegates are an implementation of the observer pattern. An interesting article on this is available here if you are interested.
A simplified example of the Observer pattern can be seen below. This example shows how “subscribers” can be attached to a stock price and receive notifications when they change. In a real-world example we would accomplish this using events, or our send out notifications via network transmission instead of outputting to the screen.
class ObserverPattern
{
// Participants:
// Subject
// Observer
// ConcreteSubject (optional)
// ConcreteObserver (optional)
public ObserverPattern()
{
IBM ibm = new IBM(120);
ibm.Attach(new Investor("John Doe"));
ibm.Attach(new Investor("Jane Doe"));
// ok create a few fluctuating prices
ibm.Price = 130;
ibm.Price = 132;
ibm.Price = 132.5;
}
}
/// <summary>
/// The Subject abstract class, as a Stock symbol
/// </summary>
public abstract class Stock
{
private string symbol;
private double price;
private List<IInvestor> investors = new List<IInvestor>();
public double Price
{
get { return price; }
set {
// If the price has changed, notify the subscribers
if (price != value)
{
price = value;
Notify();
}
}
}
public string Symbol
{
get { return symbol; }
}
public Stock(string symbol, double price)
{
this.symbol = symbol;
this.price = price;
}
public void Attach(IInvestor investor)
{
investors.Add(investor);
}
public void Detach(IInvestor investor)
{
investors.Remove(investor);
}
public void Notify()
{
foreach (IInvestor investor in investors)
{
investor.Update(this);
}
}
}
/// <summary>
/// The ConcreteSubject class, as a specific Stock symbol
/// </summary>
public class IBM : Stock
{
public IBM(double price) : base("IBM", price) { }
}
public class Investor : IInvestor
{
private string name;
private Stock stock;
public Stock Stock
{
get { return stock; }
set { stock = value; }
}
public Investor(string name)
{
this.name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("To {0}: {1} changed to {2:C}", name, stock.Symbol, stock.Price);
}
}
/// <summary>
/// The Observer interface/abstract class
/// </summary>
public interface IInvestor
{
void Update(Stock stock);
}