观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
当主题对象状态发生改变时,它的所有依赖者(观察者)都会自动收到通知并更新。
一、在 C# 中实现观察者模式通常涉及以下关键部分
IObservable<T> 和 IObserver<T> 接口:
- .NET Framework 提供了
System.IObservable<T>
和System.IObserver<T>
两个接口来标准化观察者模式的实现。IObservable<T>
表示可发送通知的对象,而IObserver<T>
定义了接收这些通知的方法。 IObserver<T>
接口中包含三个方法:OnNext(T value)
、OnError(Exception error)
和OnCompleted()
,分别用于接收到新的数据项、错误通知以及通知序列已完成。
- .NET Framework 提供了
Subject 类:
- 往往会创建一个继承自
IObservable<T>
并实现其逻辑的类,比如Subject<T>
或ReplaySubject<T>
(Rx.NET 库中),这个类负责维护订阅它的观察者的列表,并在适当的时候调用它们的方法。
- 往往会创建一个继承自
观察者实现:
- 观察者类需要实现
IObserver<T>
接口,这样当被观察者有状态变化时,可以通过OnNext
等方法得到通知并执行相应的操作。
- 观察者类需要实现
注册与解除注册:
- 被观察者提供一个方法(如
Subscribe(IObserver<T> observer)
)让观察者可以订阅事件,同时应有一个方法(如Unsubscribe(IObserver<T> observer)
或使用返回的IDisposable
对象来取消订阅)来解除订阅。
- 被观察者提供一个方法(如
事件委托和EventHandler:
- 在传统的 .NET 事件处理机制中,虽然不直接采用 IObservable/IObserver 接口,但观察者模式的概念体现在事件(Event)和委托(Delegate)上,其中
EventHandler<TEventArgs>
委托常用于表示事件处理程序,sender
参数扮演着被观察者角色,而EventArgs
子类传递的状态信息则类似于通知的数据项。
- 在传统的 .NET 事件处理机制中,虽然不直接采用 IObservable/IObserver 接口,但观察者模式的概念体现在事件(Event)和委托(Delegate)上,其中
实例教程步骤概要:
- 抽象出一个通知接口(或者直接使用现有框架提供的 Observable 接口)。
- 观察者实现该接口以接收通知。
- 被观察者维护一个观察者集合,并提供注册/取消注册的方法。
- 当被观察者状态变化时,遍历观察者集合并调用它们的更新方法,从而触发所有观察者的响应。
二、使用接口简单实现观察者模式
使用时,订阅者会注册到发布者的观察者列表中,当发布者发布新数据时,所有已注册的订阅者都会收到通知并执行相应操作。
// 定义通知接口(也可以使用现有的 INotifyPropertyChanged, IObservable<T>)
public interface INotification
{
void Notify(string message);
}
// 被观察者实现
public class Publisher : INotification
{
private List<IObserver<string>> _observers = new List<IObserver<string>>();
public void RegisterObserver(IObserver<string> observer)
{
_observers.Add(observer);
}
public void UnregisterObserver(IObserver<string> observer)
{
_observers.Remove(observer);
}
public void PublishNewData(string data)
{
foreach (var observer in _observers)
{
observer.OnNext(data);
}
}
}
// 观察者实现
public class Subscriber : IObserver<string>
{
public void OnNext(string value)
{
Console.WriteLine($"Subscriber received: {value}");
}
public void OnError(Exception error)
{
// 处理错误
}
public void OnCompleted()
{
// 清理或完成相关工作
}
}
三、使用事件(Event)和委托(Delegate)来实现观察者模式
C# delegate的使用
定义一个被观察的主题Subject
类
using System;
using System.Collections.Generic;
public class Subject
{
// 委托类型,表示观察者的行为
public delegate void StateChangedHandler(string newState);
// 事件,用于注册和注销观察者
public event StateChangedHandler StateChanged;
// 主题的状态
private string _state;
// 获取或设置主题的状态
public string State
{
get => _state;
set
{
_state = value;
// 当状态改变时,通知所有观察者
OnStateChanged();
}
}
// 受保护的方法,用于触发事件
protected virtual void OnStateChanged()
{
StateChanged?.Invoke(_state);
}
// 订阅事件的方法
public void Subscribe(StateChangedHandler handler)
{
StateChanged += handler;
}
// 取消订阅事件的方法
public void Unsubscribe(StateChangedHandler handler)
{
StateChanged -= handler;
}
}
定义观察者Observer
类
public class Observer
{
private string _name;
private Subject _subject;
public Observer(string name, Subject subject)
{
_name = name;
_subject = subject;
// 订阅主题的状态改变事件
_subject.Subscribe(HandleStateChanged);
}
private void HandleStateChanged(string newState)
{
Console.WriteLine($"Observer {_name} received new state: {newState}");
}
}
使用这些类
class Program
{
static void Main(string[] args)
{
// 创建主题
Subject subject = new Subject();
// 创建观察者并订阅主题事件
Observer observer1 = new Observer("Observer1", subject);
Observer observer2 = new Observer("Observer2", subject);
// 改变主题状态,触发事件
subject.State = "New State";
// 等待用户输入,防止程序立即退出
Console.ReadLine();
}
}
在这个例子中,Subject
类有一个State
属性,当它的值改变时,它会触发一个事件。
Observer
类在创建时订阅了这个事件,并定义了一个方法来处理这个事件。
当Subject
的State
改变时,所有订阅了StateChanged
事件的Observer
对象都会收到通知,并调用它们自己的HandleStateChanged
方法。
这就是观察者模式在C#中的基本实现。它允许主题和观察者之间保持松耦合,主题不需要知道具体有哪些观察者,而观察者也不需要知道主题的具体实现。
这提高了代码的可扩展性、可维护性和灵活性。