观察者模式

2023-09-27 15:15:02 浏览数 (1)

1.概要

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

观察者模式包含以下几个核心角色:

  • 主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。
  • 观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
  • 具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。
  • 具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。

观察者模式通过将主题和观察者解耦,实现了对象之间的松耦合。当主题的状态发生改变时,所有依赖于它的观察者都会收到通知并进行相应的更新。

观察者模式有哪些使用场景?

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

举例说明:

  1. 气象站数据更新
    • 场景说明:一个气象站收集温度、湿度和气压等数据,并需要通知多个设备来更新显示这些数据。
    • 观察者模式实现:气象站是主题,多个显示设备是观察者。当气象数据更新时,主题通知观察者,观察者根据需要更新自己的显示。
  2. 股票市场监控
    • 场景说明:投资者关心股票价格的变化,股票价格的变化需要通知所有关注该股票的投资者。
    • 观察者模式实现:股票市场是主题,投资者是观察者。当股票价格变化时,市场通知所有投资者。
  3. 邮件订阅
    • 场景说明:用户可以订阅不同类型的邮件通知,如新闻、促销、通知等。
    • 观察者模式实现:邮件系统是主题,用户是观察者。当有新的邮件通知时,系统通知订阅了相关类型的用户。
  4. 按钮点击事件
    • 场景说明:在图形用户界面中,多个按钮需要在点击时执行不同的操作。
    • 观察者模式实现:每个按钮是一个主题,执行的操作是观察者。当按钮被点击时,主题通知相应的观察者执行操作。
  5. 消息发布-订阅系统
    • 场景说明:构建一个消息发布-订阅系统,允许发布者发布消息,而订阅者可以选择订阅感兴趣的消息。
    • 观察者模式实现:消息发布者是主题,订阅者是观察者。发布者发布消息,观察者订阅感兴趣的消息。

2.详细内容

代码语言:javascript复制
using System;
using System.Collections.Generic;

// 定义观察者接口
public interface IObserver<T>
{
    void Update(T data);
}

// 定义被观察者接口
public interface IObservable<T>
{
    void Attach(IObserver<T> observer);
    void Detach(IObserver<T> observer);
    void Notify(T data);
}

// 实现被观察者
public class Subject<T> : IObservable<T>
{
    private List<IObserver<T>> observers = new List<IObserver<T>>();

    public void Attach(IObserver<T> observer)
    {
        observers.Add(observer);
    }

    public void Detach(IObserver<T> observer)
    {
        observers.Remove(observer);
    }

    public void Notify(T data)
    {
        foreach (var observer in observers)
        {
            observer.Update(data);
        }
    }
}

// 实现观察者
public class ConcreteObserver<T> : IObserver<T>
{
    private string name;

    public ConcreteObserver(string name)
    {
        this.name = name;
    }

    public void Update(T data)
    {
        Console.WriteLine($"{name} 收到数据: {data}");
    }
}

class Program
{
    static void Main()
    {
        Subject<int> subject = new Subject<int>();
        var observer1 = new ConcreteObserver<int>("Observer 1");
        var observer2 = new ConcreteObserver<int>("Observer 2");

        subject.Attach(observer1);
        subject.Attach(observer2);

        subject.Notify(42);

        subject.Detach(observer1);

        subject.Notify(99);
    }
}

0 人点赞