// This pattern defines a one-to-many dependency between objects so that when one object changes state,
// all its dependents are notified and updated automatically.
// Further, if use template to parameterize the type of class, we can get a more flexible implementation.
Here, I give a C# version implementation.
using System;
using System.Collections.Generic;
using System.Text;
namespace Observer
{
// subject.cs
interface ISubject
{
void RegisterObserver(Observer o);
void RemoveObserver(Observer o);
void NotifyObservers();
}
class WeatherStation : ISubject
{
public void RegisterObserver(Observer o)
{
if (o is Observer)
{
if (!listeners.Contains(o))
listeners.Add(o);
}
}
public void RemoveObserver(Observer o)
{
if (o is Observer)
listeners.Remove(o);
}
public void NotifyObservers()
{
if (isChanged)
{
foreach (Observer o in listeners)
o.Update(temperature, humidity, pressure);
}
isChanged = false;
}
private void SetChanged()
{
isChanged = true;
}
public float GetTemperature()
{
return temperature;
}
public float GetHumidity()
{
return humidity;
}
public float GetPressure()
{
return pressure;
}
public void SetElements(float t, float h, float p)
{
temperature = t;
humidity = h;
pressure = p;
SetChanged();
NotifyObservers();
}
public WeatherStation()
{
listeners = new List<Observer>();
temperature = 0;
humidity = 0;
pressure = 0;
isChanged = false;
}
private List<Observer> listeners;
private float temperature;
private float humidity;
private float pressure;
private bool isChanged;
}
// Observer.cs
interface Observer
{
void Update(float t, float h, float p);
}
interface DisplayElement
{
void Display();
}
class ObserverOne : Observer, DisplayElement
{
public ObserverOne(ISubject s)
{
temperature = 0;
humidity = 0;
aSubject = s;
aSubject.RegisterObserver(this);
}
public void Update(float t, float h, float p)
{
temperature = t;
humidity = h;
Display();
}
public void Display()
{
Console.WriteLine("ObserverOne: Temperature: {0}/tHumidity: {1}", temperature, humidity);
}
public void RegisterMyself()
{
aSubject.RegisterObserver(this);
}
public void RemoveMyself()
{
aSubject.RemoveObserver(this);
}
private float temperature;
private float humidity;
private ISubject aSubject;
}
class ObserverTwo : Observer, DisplayElement
{
public ObserverTwo(ISubject s)
{
temperature = 0;
pressure = 0;
aSubject = s;
aSubject.RegisterObserver(this);
}
public void Update(float t, float h, float p)
{
temperature = t;
pressure = p;
Display();
}
public void Display()
{
Console.WriteLine("ObserverTwo: Temperature: {0}/tPressure: {1}", temperature, pressure);
}
public void RegisterMyself()
{
aSubject.RegisterObserver(this);
}
public void RemoveMyself()
{
aSubject.RemoveObserver(this);
}
private float temperature;
private float pressure;
private ISubject aSubject;
}
// main program
class Program
{
static void Main(string[] args)
{
WeatherStation aData = new WeatherStation();
ObserverOne aOne = new ObserverOne(aData);
ObserverTwo aTwo = new ObserverTwo(aData);
aData.SetElements(23.0f, 10.1f, 0.7f);
aOne.RemoveMyself();
aTwo.RegisterMyself();
aOne.RegisterMyself();
aData.SetElements(18.0f, 7.7f, 0.3f);
}
}
}
Either an interface implemetation or an inheritance impplemetation is still imperfect. Both of them have some flaws. For details pls refer to "Head First Design Pattern" chapter2.