Observer design pattern | Behavioral design pattern
Observer design pattern
The Observer design pattern is a behavioral design pattern where an object, known as the subject, maintains a list of its dependents, called observers, that are notified of any state changes, typically by calling one of their methods. This pattern is widely used to implement distributed event handling systems.
The key components of the Observer design pattern are:
1. Subject: This is the object that holds the state and notifies observers of any changes. It provides methods to attach, detach, and notify observers.
2. Observer: Objects that depend on the state of the subject. They define an update method that is called by the subject to notify them of changes.
3. ConcreteSubject: This is a specific implementation of the subject. It maintains the state that observers are interested in and sends notifications to its observers when the state changes.
4. ConcreteObserver: Specific implementation of the observer. It registers with a concrete subject to receive updates and implements the update method to respond to changes in the subject's state.
By using these components, the Observer pattern allows a flexible and loosely coupled communication between objects, facilitating the design of systems where changes in one object trigger actions in dependent objects.
When to use:
- Use the Observer pattern when an object's state changes and you want other objects to be notified automatically.
- When you have a one-to-many dependency between objects, and changing one object should notify all its dependents.
Why to use:
- It promotes loose coupling between objects. Observers don't need to know the details of the subject, just the interface.
- It allows for a distributed event handling system where multiple objects can react to changes in another object without being tightly coupled.
Where to use:
- In graphical user interface frameworks for handling events and updates.
- In distributed systems where changes in one part of the system should trigger actions in other parts.
- In systems where you want to decouple classes that need to communicate, making the system more modular and easier to maintain.
Overall, the Observer pattern is beneficial when you need a flexible and decoupled way to handle communication between objects that exhibit a one-to-many relationship.
Example of the Observer pattern in C#:
using System;
using System.Collections.Generic;
// Subject
public class Subject
{
private int _state;
private List<IObserver> _observers = new List<IObserver>();
public int State
{
get { return _state; }
set
{
_state = value;
NotifyObservers();
}
}
public void Attach(IObserver observer)
{
_observers.Add(observer);
}
public void Detach(IObserver observer)
{
_observers.Remove(observer);
}
private void NotifyObservers()
{
foreach (var observer in _observers)
{
observer.Update();
}
}
}
// Observer
public interface IObserver
{
void Update();
}
// ConcreteObserver
public class ConcreteObserver : IObserver
{
private string _name;
private Subject _subject;
public ConcreteObserver(string name, Subject subject)
{
_name = name;
_subject = subject;
_subject.Attach(this);
}
public void Update()
{
Console.WriteLine($"Observer {_name} has been notified. New state: {_subject.State}");
}
}
// Example usage
class Program
{
static void Main()
{
Subject subject = new Subject();
ConcreteObserver observer1 = new ConcreteObserver("Observer1", subject);
ConcreteObserver observer2 = new ConcreteObserver("Observer2", subject);
subject.State = 10;
subject.State = 20;
// Output:
// Observer Observer1 has been notified. New state: 10
// Observer Observer2 has been notified. New state: 10
// Observer Observer1 has been notified. New state: 20
// Observer Observer2 has been notified. New state: 20
}
}
In this example, `Subject` maintains a state and notifies its observers when the state changes. `ConcreteObserver` objects subscribe to the subject and receive notifications. The `Main` method demonstrates how changing the subject's state triggers notifications to all attached observers.
A real-world example of the Observer pattern can be found in the implementation of a stock market monitoring system.
- Subject (Stock): Represents a stock that can change its value over time.
- Observer (Investor): Represents an investor interested in monitoring the value of certain stocks.
Here's how it could be structured:
using System;
using System.Collections.Generic;
// Subject
public class Stock
{
private string _symbol;
private double _price;
private List<IInvestor> _investors = new List<IInvestor>();
public Stock(string symbol, double price)
{
_symbol = symbol;
_price = price;
}
public void Attach(IInvestor investor)
{
_investors.Add(investor);
}
public void Detach(IInvestor investor)
{
_investors.Remove(investor);
}
public double Price
{
get { return _price; }
set
{
_price = value;
NotifyInvestors();
}
}
private void NotifyInvestors()
{
foreach (var investor in _investors)
{
investor.Update(this);
}
}
}
// Observer
public interface IInvestor
{
void Update(Stock stock);
}
// ConcreteObserver
public class Investor : IInvestor
{
private string _name;
public Investor(string name)
{
_name = name;
}
public void Update(Stock stock)
{
Console.WriteLine($"Notified {_name} of {_stock.Symbol}'s price change to {stock.Price}");
}
}
// Example usage
class Program
{
static void Main()
{
Stock stock = new Stock("ABC", 100.0);
IInvestor investor1 = new Investor("Investor1");
IInvestor investor2 = new Investor("Investor2");
stock.Attach(investor1);
stock.Attach(investor2);
stock.Price = 105.0;
// Output:
// Notified Investor1 of ABC's price change to 105
// Notified Investor2 of ABC's price change to 105
}
}
In this example, when the stock price changes, all attached investors are notified. This mirrors how investors in real life might be interested in tracking the performance of specific stocks and taking actions based on their changes in value.
Comments
Post a Comment