C#中观察者模式(Observer Pattern)深入解析

观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象间的一对多依赖关系,使得当一个对象的状态发生变化时,其所有依赖者(观察者)都会自动收到通知并更新。这种模式广泛应用于事件处理、消息订阅系统等领域。

一、观察者模式的核心概念

观察者模式涉及两个主要角色:

  1. 主题(Subject):也称为"被观察者",它是一个对象,它的状态发生变化时,通知所有已注册的观察者。主题通常提供注册、注销和通知观察者的功能。

  2. 观察者(Observer):也称为"订阅者",它是依赖于主题的对象,观察者会在主题发生变化时接收通知并做出响应。

通过观察者模式,主题与观察者之间解耦,主题无需知道观察者的具体实现,观察者只需要实现通知接口即可。

二、观察者模式的类图

观察者模式的典型类图如下:

复制代码
       +---------------+      +----------------+
       |   Subject     |      |    Observer    |
       |---------------|      |----------------|
       | +Attach()     |      | +Update()      |
       | +Detach()     |<---->|                |
       | +Notify()     |      +----------------+
       +---------------+        
            |
        +------------+ 
        | Concrete  |
        |  Subject  |
        +------------+ 
            |
        +--------------------+
        | Concrete Observer  |
        +--------------------+
  • Subject(主题/被观察者):具有状态的对象,维护观察者列表,并提供方法用于注册、注销观察者。

  • Observer(观察者) :对主题的状态变化做出响应的接口,通常会有一个 Update() 方法。

  • ConcreteSubject(具体主题) :实现了 Subject 类,保存主题的状态,并在状态变化时通知观察者。

  • ConcreteObserver(具体观察者) :实现了 Observer 接口,处理主题状态变化时的具体行为。

三、观察者模式的应用场景
  1. GUI事件处理:在图形用户界面(GUI)中,观察者模式广泛用于事件处理。例如,当按钮被点击时,系统通知所有注册的监听器来响应这个事件。

  2. 发布-订阅系统:例如,新闻应用中的用户订阅和接收新闻更新,或股票价格更新系统,用户可以订阅某个股票的变化。

  3. 日志记录系统:当应用程序发生某些变化时,系统可以通知所有注册的观察者(如日志记录器)来进行相应操作。

四、C#实现观察者模式

下面是一个简单的 C# 实现观察者模式的例子。在这个例子中,NewsAgency 类是一个主题,Subscriber 类是观察者。当新闻发布时,所有订阅者都会接收到更新的新闻。

复制代码
using System;
using System.Collections.Generic;

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

// 主题接口
public interface ISubject
{
    void Attach(IObserver observer);   // 注册观察者
    void Detach(IObserver observer);   // 注销观察者
    void Notify();                     // 通知观察者
}

// 具体主题(被观察者)
public class NewsAgency : ISubject
{
    private List<IObserver> _observers = new List<IObserver>();  // 观察者列表
    private string _latestNews;

    public string LatestNews
    {
        get { return _latestNews; }
        set
        {
            _latestNews = value;
            Notify();  // 一旦新闻变化,通知所有观察者
        }
    }

    public void Attach(IObserver observer)
    {
        _observers.Add(observer);
    }

    public void Detach(IObserver observer)
    {
        _observers.Remove(observer);
    }

    public void Notify()
    {
        foreach (var observer in _observers)
        {
            observer.Update(_latestNews);  // 通知所有观察者
        }
    }
}

// 具体观察者
public class Subscriber : IObserver
{
    public string Name { get; }

    public Subscriber(string name)
    {
        Name = name;
    }

    public void Update(string news)
    {
        Console.WriteLine($"{Name} received news: {news}");
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 创建新闻机构(主题)
        NewsAgency newsAgency = new NewsAgency();

        // 创建多个订阅者(观察者)
        Subscriber subscriber1 = new Subscriber("John");
        Subscriber subscriber2 = new Subscriber("Jane");
        Subscriber subscriber3 = new Subscriber("Alex");

        // 注册订阅者
        newsAgency.Attach(subscriber1);
        newsAgency.Attach(subscriber2);
        newsAgency.Attach(subscriber3);

        // 发布新闻
        Console.WriteLine("Publishing news...");
        newsAgency.LatestNews = "Breaking News: New technology launched!";

        // 注销订阅者
        newsAgency.Detach(subscriber2);

        // 发布新的新闻
        Console.WriteLine("\nPublishing another news...");
        newsAgency.LatestNews = "Breaking News: Major event happening!";
    }
}
五、代码解析
  1. IObserver接口 :定义了Update方法,供观察者类实现。当主题发生变化时,Update方法会被调用。

  2. ISubject接口 :定义了Attach(注册观察者)、Detach(注销观察者)和Notify(通知观察者)方法。Notify方法会通知所有已注册的观察者。

  3. NewsAgency(新闻机构)类 :实现了 ISubject 接口,维护了一个观察者列表(_observers)。当新闻更新时,调用 Notify 方法通知所有订阅者。

  4. Subscriber(订阅者)类 :实现了 IObserver 接口,包含一个 Update 方法,每当主题状态发生变化时,Update 方法就会被调用,接收最新的新闻。

  5. Main 方法 :在 Main 方法中,创建了一个新闻机构并注册了几个订阅者。当新闻更新时,所有订阅者都会接收到更新的内容。如果某个订阅者被注销,它就不会再收到未来的新闻更新。

六、观察者模式的优缺点
优点:
  1. 解耦:主题(被观察者)和观察者之间解耦,主题不需要知道观察者的具体实现,观察者也不需要知道主题的细节。它们仅通过接口交互。

  2. 动态响应:观察者可以在运行时动态注册和注销,可以灵活地增加或减少订阅者。

  3. 一对多依赖关系:主题对象一旦发生变化,所有依赖的观察者都会被自动通知,并更新状态。

缺点:
  1. 通知开销:如果观察者很多,主题在通知时可能会产生较大的性能开销。

  2. 不完全控制:由于观察者可以随时注册或注销,可能会存在一些不必要的更新和通知,尤其是当观察者很少或者在不需要的情况下仍被通知时。

  3. 循环依赖:如果观察者中有回调导致主题状态变化,可能会产生循环依赖,导致死循环。

七、总结

观察者模式是一种非常有用的设计模式,适用于实现一对多依赖的场景,尤其在事件驱动系统中应用广泛。在C#中,观察者模式能够简洁而灵活地实现对象间的通信,解耦了主题和观察者之间的关系,具有良好的扩展性和可维护性。

相关推荐
兰亭序咖啡18 分钟前
学透Spring Boot — 018. 优雅支持多种响应格式
java·spring boot·后端
小雨凉如水22 分钟前
docker 常用命令
java·docker·eureka
the_nov38 分钟前
19.TCP相关实验
linux·服务器·网络·c++·tcp/ip
高山流水&上善41 分钟前
医药档案区块链系统
java·springboot
南汐以墨1 小时前
探秘JVM内部
java·jvm
Craaaayon1 小时前
Java八股文-List集合
java·开发语言·数据结构·list
西元.1 小时前
详解 Redis repl_backlog_buffer(如何判断增量同步)
数据库·redis·缓存
信徒_2 小时前
Spring 怎么解决循环依赖问题?
java·后端·spring
Y淑滢潇潇2 小时前
RHCSA Linux 系统创建文件
linux·运维·服务器
2301_794461572 小时前
多线程编程中的锁策略
java·开发语言