C# 怎么实现一个观察者模式_C# 观察者模式实现方法详解

C#中实现观察者模式的核心是定义主题与观察者,通过接口、事件或IObservable方式实现状态变更时的自动通知,适用于事件驱动场景。

在 C# 中实现观察者模式,核心是定义一个被观察对象(主题)和多个观察者,当主题状态发生变化时,自动通知所有注册的观察者。这种设计模式非常适合处理事件驱动的场景,比如 UI 更新、消息广播等。

观察者模式的基本结构

观察者模式包含两个主要角色:

  • Subject(主题):维护观察者列表,提供注册、注销和通知方法。
  • Observer(观察者):实现一个更新接口,用于接收主题的通知。

在 C# 中,可以通过接口和委托两种方式来实现。下面分别介绍具体做法。

使用接口手动实现观察者模式

定义观察者和主题接口,让具体类实现它们。

示例代码:

// 观察者接口
public interface IObserver
{
    void Update(string message);
}

// 主题接口 public interface ISubject { void Attach(IObserver observer); void Detach(IObserver observer); void Notify(string message); }

// 具体主题 public class NewsAgency : ISubject { private List _observers = new List();

public void Attach(IObserver observer) => _observers.Add(observer);
public void Detach(IObserver observer) => _observers.Remove(observer);

public void Notify(string news)
{
    foreach (var observer in _observers)
    {
        observer.Update(news);
    }
}

// 模拟新闻发布
public void PublishNews(string news)
{
    Console.WriteLine($"新闻机构发布:{news}");
    Notify(news);
}

}

// 具体观察者 public class NewsChannel : IObserver { private string _name;

public NewsChannel(string name) => _name = name;

public void Update(string message)
{
    Console.WriteLine($"{_name} 收到新闻:{message}");
}

}

使用示例:

var agency = new NewsAgency();
var channelA = new NewsChannel("央视");
var channelB = new NewsChannel("凤凰");

agency.Attach(channelA); agency.Attach(channelB);

agency.PublishNews("今日天气晴朗");

// 输出: // 新闻机构发布:今日天气晴朗 // 央视 收到新闻:今日天气晴朗 // 凤凰 收到新闻:今日天气晴朗

利用 C# 委托和事件简化实现

C# 的事件机制天生适合观察者模式。通过 eventdelegate,可以更简洁地实现松耦合通信。

示例代码:

public class Stock
{
    // 定义委托
    public delegate void PriceChangedHandler(string symbol, double price);
// 定义事件
public event PriceChangedHandler PriceChanged;

private string _symbol;
private double _price;

public Stock(string symbol, double price)
{
    _symbol = symbol;
    _price = price;
}

public double Price
{
    get => _price;
    set
    {
        _price = value;
        OnPriceChanged(); // 触发事件
    }
}

protected virtual void OnPriceChanged()
{
    PriceChanged?.Invoke(_symbol, _price);
}

}

观察者订阅事件:

var stock = new Stock("AAPL", 150.0);

// 订阅事件 stock.PriceChanged += (symbol, price) => { Console.WriteLine($"股票 {symbol} 价格变更为:{price}"); };

stock.Price = 155.0; // 输出:股票 AAPL 价格变更为:155

这种方式更符合 C# 的编程习惯,代码更简洁,且线程安全由语言机制部分保障。

使用 IObservable 和 IObserver 接口(响应式扩展)

C# 还提供了内置的 IObservableIObserver 接口,属于 .NET 的响应式扩展(Reactive Extensions, Rx),适用于更复杂的异步数据流场景。

public class Sensor : IObservable
{
    private List> _observers = new List>();
public IDisposable Subscribe(IObserver observer)
{
    if (!_observers.Contains(observer))
        _observers.Add(observer);

    return new Unsubscriber(_observers, observer);
}

public void Measure(double value)
{
    foreach (var observer in _observers)
        observer.OnNext(value);
}

private class Unsubscriber : IDisposable
{
    private List> _observers;
    private IObserver _observer;

    public Unsubscriber(List> observers, IObserver observer)
    {
        _observers = observers;
        _observer = observer;
    }

    public void Dispose()
    {
        _observers.Remove(_observer);
    }
}

}

使用方式:

var sensor = new Sensor();

var observer = new MyObserver(); var subscription = sensor.Subscribe(observer);

sensor.Measure(23.5); // 触发通知

subscription.Dispose(); // 取消订阅

其中 MyObserver 需要实现 IObserver 接口。

基本上就这些。C# 提供了多种实现观察者模式的方式:手动接口实现适合学习原理,事件机制最常用也最自然,而 IObservable 则适用于高级异步场景。选择哪种方式取决于项目复杂度和需求。