C#中的观察者模式

woo*_*gie 5 c# design-patterns observer-pattern

我正在阅读(出色的)书,Head First Design Patterns并且需要对观察者模式进行一些说明。下面的一些代码模拟了一个侦听天气模式更新的设备(CurrentConditionDisplay)。

接口:

public interface ISubject
{
    void RegisterObserver(IObserver obs);
    void RemoveObserver(IObserver obs);
    void NotifyObservers();
}
public interface IDisplay
{
    string Display();
}
public interface IObserver
{
    void Update(float temperature, float humidity, float pressure);
}
Run Code Online (Sandbox Code Playgroud)

观察者

public class CurrentConditionDisplay : IObserver, IDisplay
{
    private float temperature;
    private float humidity;
    private float pressure;
    private ISubject weatherData;
    public CurrentConditionDisplay(ISubject weatherData)
    {
        this.weatherData = weatherData;
        this.weatherData.RegisterObserver(this);

    }
    public string Display()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("Welcome to Current Condition Display...");
        sb.AppendLine(this.temperature.ToString());
        sb.AppendLine(this.humidity.ToString());
        sb.AppendLine(this.pressure.ToString());
        return sb.ToString();
    }

    public void Update(float temperature, float humidity, float pressure)
    {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
    }
}
Run Code Online (Sandbox Code Playgroud)

学科

public class WeatherData : ISubject
{
    private List<IObserver> observersList;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData()
    {
        observersList = new List<IObserver>();
    }
    public void RegisterObserver(IObserver obs)
    {
        observersList.Add(obs);
    }

    public void RemoveObserver(IObserver obs)
    {
        int index = observersList.IndexOf(obs);
        if (index >= 0)
        {
            observersList.RemoveAt(index);
        }
    }
    public void MeasurementsChanged()
    {
        Console.WriteLine("There is new data available...");
        NotifyObservers();
    }
    public void NotifyObservers()
    {
        foreach (IObserver observer in observersList)
        {
            observer.Update(temperature, humidity, pressure);
        }
    }
    public void SetMeasurements(float temperature, float humidity, float pressure)
    {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        MeasurementsChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

要在Program.cs中使用这些类,我需要创建一次实例WeatherData并将该对象作为参数传递给的构造函数CurrentConditionDisplay。我在当前设置中看到的一个问题是,IObserver有一种方法将Updatetemperature, humidity, pressure作为参数。我看不到主题(WeatherData)必须首先具有这些字段。我应该添加另一个接口或抽象基类以确保在SetMeasurements调用时,该方法中要更新的所有字段实际上都在Observer吗?

Jef*_*f B 2

我和你有同样的感觉......有一个相当通用的听起来IObserver界面有一个特定的方法签名,实际上适用于观察WeatherData感觉恶心的时候!

我更愿意有这样的东西:

public interface IObserver<T>
{
    void Update(T updatedData);
}
Run Code Online (Sandbox Code Playgroud)

对于一个看起来像这样的观察者(这里剪掉了一些额外的代码):

public class CurrentConditionDisplay : IObserver<WeatherUpdate>, IDisplay
{
    public CurrentConditionDisplay(ISubject<WeatherUpdate> weatherData)
    {
        this.weatherData = weatherData;
        this.weatherData.RegisterObserver(this);   
    }

    public void Update(WeatherUpdate update)
    {
        this.temperature = update.Temperature;
        this.humidity = update.Humidity;
        this.pressure = update.Pressure;
    }
}
Run Code Online (Sandbox Code Playgroud)

为了让自己清楚,我的通用TIObserver<T>一个封装天气更新的对象:

public WeatherUpdate
{
    public float Temperature;
    public float Humidity;
    public float Pressure;
}
Run Code Online (Sandbox Code Playgroud)

并且还ISubject必须更改为包含通用参数:

public interface ISubject<T>
{
    void RegisterObserver(IObserver<T> obs);
    void RemoveObserver(IObserver<T> obs);
    void NotifyObservers();
}
Run Code Online (Sandbox Code Playgroud)