C# 中的观察者模式:经典与现代

本文旨在为中级及以上的C#程序员提供观察者模式的深入理解。观察者模式,也称为发布-订阅模式,是一种设计模式,允许对象之间的松耦合,使得当一个对象状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。在C#中,观察者模式通过事件机制得到了直接的支持,但同时也带来了一些需要特别注意的多线程问题。

经典观察者模式

观察者模式定义了对象之间的一对多依赖关系,当一个对象(Subject)的状态发生变化时,所有依赖于它的对象(Observers)都会得到通知并更新。在C#中,虽然已经通过事件关键字集成了观察者模式,但开发者仍然可以选择实现自己的版本。以下是经典观察者模式的实现示例:

public class Args { } public abstract class ASubject { protected List<IObserver> observersList = new List<IObserver>(); public void AddObserver(IObserver observer) { observersList.Add(observer); } public void RemoveObserver(IObserver observer) { observersList.Remove(observer); } } public interface IObserver { void Update(object subject, Args args); } public class Subject : ASubject { public string SubjectState = null; public void NotifyObservers() { ArgsSubject args = new ArgsSubject(); args.SubjectState = this.SubjectState; foreach (IObserver o in observersList) { o.Update(this, args); } } } public class Observer : IObserver { private string name; private string observerState; public Observer(string name) { this.name = name; } public void Update(object s, Args args) { observerState = ((ArgsSubject)args).SubjectState; Console.WriteLine("Observer {0}'s new state is {1}", name, observerState); } } public class ArgsSubject : Args { public string SubjectState = null; } class Client { public static void Main(string[] args) { Subject s = new Subject(); s.AddObserver(new Observer("1")); s.AddObserver(new Observer("2")); s.AddObserver(new Observer("3")); // Change subject state and notify observers s.SubjectState = "ABC123"; s.NotifyObservers(); Console.ReadLine(); } }

在上述代码中,定义了Subject和Observer两个类,以及一个Args类用于传递状态信息。Subject类维护了一个观察者列表,并提供了添加和移除观察者的方法。当Subject的状态发生变化时,它会通知所有的观察者。

现代观察者模式在C#中的实现

C#语言通过事件机制实现了观察者模式。在C#中,Subject对应于事件,Observer对应于事件处理程序(EventHandler)。以下是使用事件机制实现观察者模式的代码示例:

public class Subject { public event EventHandler<EventArgsSubject> SubjectEvent; public string SubjectState; public void NotifyObservers() { EventArgsSubject args = new EventArgsSubject(); args.SubjectState = this.SubjectState; if (SubjectEvent != null) { SubjectEvent(this, args); } } } public class Observer { private string name; private string observerState; public Observer(string name) { this.name = name; } public void Update(object subject, EventArgsSubject args) { observerState = args.SubjectState; Console.WriteLine("Observer {0}'s new state is {1}", name, observerState); } } public class EventArgsSubject : EventArgs { public string SubjectState = null; } class Client { public static void Main(string[] args) { Subject s = new Subject(); s.SubjectEvent += (new Observer("1")).Update; s.SubjectEvent += (new Observer("2")).Update; s.SubjectEvent += (new Observer("3")).Update; // Change subject state and notify observers s.SubjectState = "ABC123"; s.NotifyObservers(); Console.ReadLine(); } }

在现代的实现中,使用事件来代替了观察者列表。当Subject的状态发生变化时,它会触发一个事件,所有订阅了该事件的处理程序都会被调用。这种方式简化了代码,并且更加符合C#的编程习惯。

事件机制的同步调用

需要注意的是,事件机制实际上是在单线程上同步调用的。这意味着,所有订阅了事件的处理程序将会按照它们订阅的顺序依次执行,并且一个处理程序的执行会阻塞线程,直到其执行完成。如果某个处理程序抛出异常,那么后续的处理程序将不会被执行。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485