本文旨在为中级及以上的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#中,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#的编程习惯。
需要注意的是,事件机制实际上是在单线程上同步调用的。这意味着,所有订阅了事件的处理程序将会按照它们订阅的顺序依次执行,并且一个处理程序的执行会阻塞线程,直到其执行完成。如果某个处理程序抛出异常,那么后续的处理程序将不会被执行。