田敏
返回博客列表
技术

观察者模式

田敏
2024-11-272 分钟阅读
Design PatternSoftware Engineering

参考链接:观察者模式 | 菜鸟教程 (runoob.com)

观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

意图

创建了对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新。

主要解决的问题

  • 观察者模式解决的是一个对象状态改变时,如何自动通知其他依赖对象的问题,同时保持对象间的低耦合和高协作性。

使用场景

  • 当一个对象的状态变化需要同时更新其他对象时。

实现方式

  • 定义观察者接口:包含一个更新方法。
  • 创建具体观察者:实现观察者接口,定义接收到通知时的行为。
  • 定义主题接口:包含添加、删除和通知观察者的方法。
  • 创建具体主题:实现主题接口,管理观察者列表,并在状态改变时通知它们。

实现

观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。

ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式。

观察者模式的 UML 图

在.NET中的使用

在 .NET 中,观察者模式广泛用于处理事件驱动的应用程序、实时监控和跨组件通信等场景。以下是一些典型的应用场景:

1. 事件机制

  • 场景:观察者模式直接体现在 .NET 事件机制中,利用 event 关键字定义的事件可以让订阅者(观察者)注册以获取通知。
  • 例子Button 点击事件。在 WinForms 或 WPF 中,可以为一个按钮的 Click 事件添加多个事件处理程序,当按钮被点击时通知所有处理程序。
  • 代码示例
    Button button = new Button();
    button.Click += (sender, e) => Console.WriteLine("Button clicked!");
    

2. 数据绑定和属性变更通知

  • 场景INotifyPropertyChanged 接口常用于 WPF 和 WinForms 应用程序的数据绑定。此接口允许对象属性变更后通知 UI 更新,从而实现数据绑定。
  • 例子:MVVM 模式中的 ViewModel 层使用 INotifyPropertyChanged 通知视图更新。
  • 代码示例
    public class Person : INotifyPropertyChanged
    {
        private string name;
        public string Name
        {
            get => name;
            set
            {
                if (name != value)
                {
                    name = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
                }
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

3. 文件系统监控(FileSystemWatcher

  • 场景FileSystemWatcher 类用于监控文件或目录的变化,并通知订阅者文件是否创建、修改、删除或重命名。
  • 例子:实现文件夹或文件变更监听的系统。
  • 代码示例
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = @"C:\temp";
    watcher.Changed += (sender, e) => Console.WriteLine($"File {e.FullPath} was changed");
    watcher.EnableRaisingEvents = true;
    

4. 观察者模式在 Rx.NET(Reactive Extensions)中的实现

  • 场景:使用观察者模式处理流式数据。通过 IObservable<T>IObserver<T> 接口,Rx.NET 提供了大量支持异步和事件驱动的数据流处理。
  • 例子:实时数据流处理,比如股票数据监控。
  • 代码示例
    IObservable<int> numbers = Observable.Range(1, 10);
    numbers.Subscribe(
        x => Console.WriteLine($"Received {x}"),
        ex => Console.WriteLine($"Error: {ex.Message}"),
        () => Console.WriteLine("Completed"));
    

5. ASP.NET 中的信号通知和广播

  • 场景:在 ASP.NET Core SignalR 中,观察者模式用于实现实时通信。客户端可以订阅特定的通知,服务器在有更新时广播消息,所有订阅的客户端会收到该更新。
  • 例子:即时聊天应用、股票价格实时更新。
  • 代码示例
    // 定义一个 Hub
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
    

6. 日志订阅系统

  • 场景:应用程序可以将多个日志观察者(如文件、数据库、控制台)注册到日志服务中。日志服务在记录日志时会通知所有观察者。
  • 例子:通过依赖注入注册多种日志提供程序,方便扩展和统一管理日志记录。
  • 代码示例
    public class Logger
    {
        private readonly List<ILogObserver> _observers = new List<ILogObserver>();
        
        public void RegisterObserver(ILogObserver observer) => _observers.Add(observer);
        public void Log(string message)
        {
            foreach (var observer in _observers)
            {
                observer.Update(message);
            }
        }
    }
    

总结

在 .NET 中,观察者模式提供了基于事件的松耦合设计,适用于实现通知广播、多订阅和异步更新等场景。无论是在 UI 数据绑定、文件系统监听,还是在事件驱动的数据流处理中,观察者模式都提供了简便的解决方案,使组件间通信更高效。

版权协议:MIT返回列表