示例代码为了尽可能突显设计模式的特征,采用了极简代码。尽量避免其他代码对理解设计模式产生干扰

定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
简而言之就是,观察者模式可以在被观察者的某个指定动作执行时,通知到其对应的观察者。使得观察者们可以即时做出相应的反应。

结构导图

观察者模式导图


示例项目简述

项目结构

示例代码的大概意图其实就是实现一个下载器。当指定文件下载完成后,会通知其观察者们,以便这些观察者可以根据各自需求处理下载下来的文件。

接下来,请见具体代码。

代码

抽象观察者

/// <summary>
/// 抽象观察者
/// </summary>
interface IObserver
{
    void DoUpdate();
}

其实这个抽象观察者,只是一个简单的接口。所有具体观察者都将继承自它。

具体观察者

/// <summary>
/// 具体观察者-文件下载完成后,备份文件。
/// </summary>
class Observer1 : IObserver
{
    public void DoUpdate()
    {
        Console.WriteLine("观察者1已将文件备份。");
    }
}

/// <summary>
/// 具体观察者-文件下载完成后,压缩文件。
/// </summary>
class Observer2 : IObserver
{
    public void DoUpdate()
    {
        Console.WriteLine("观察者2已将文件压缩。");
    }
}

/// <summary>
/// 具体观察者-文件下载完成后,发送文件。
/// </summary>
class Observer3 : IObserver
{
    public void DoUpdate()
    {
        Console.WriteLine("观察者3已将文件发送给相关同事。");
    }
}

以上是三个极简的具体观察者。它们分别在收到下载成功的通知后,对文件进行备份压缩转发

既然观察者们已经准备好了,那么该轮到被观察者了。

被观察者

一般,被观察者会相对复杂一点。因为它不单单要提供某动作的执行方法,也要提供注册及注销观察者的方法。
当一个被观察者被创建后,首先需要为其绑定一些其必需的观察者(如果需要的话)。观察者们被绑定成功后,这个观察者列表将被被观察者维护着。
若被观察者的某个动作执行完成后,如果需要通知观察者,那么就可以通过这个观察者列表,依次通知到所有需要被通知的观察者。

/// <summary>
/// 文件下载器-被观察者
/// </summary>
class Downloader
{
    /// <summary>
    /// 观察者列表
    /// </summary>
    public readonly HashSet<IObserver> observers;

    public Downloader()
    {
        observers = new HashSet<IObserver>();
    }

    /// <summary>
    /// 注册观察者
    /// </summary>
    public bool AddObserver(IObserver _observer)
    {
        return observers.Add(_observer);
    }

    /// <summary>
    /// 注销观察者
    /// </summary>
    public bool RemoveObserver(IObserver _observer)
    {
        return observers.Remove(_observer);
    }

    /// <summary>
    /// 下载
    /// </summary>
    public void Download()
    {
        Console.WriteLine("文件开始下载。");
        Console.WriteLine("文件下载中···");
        Thread.Sleep(3000);// 模拟文件下载的耗时过程
        Console.WriteLine("文件下载完成。");
        foreach (var observer in observers)
        {
            observer.DoUpdate();
        }
    }
}

如上代码中,当Download方法内,文件下载成功后,就会遍历观察者列表,逐个通知对应的观察者,告诉它们:文件下载成功了,你该干嘛干嘛去

客户端

请看客户端代码

// 实例化下载器
var downloader = new Downloader();

// 创建观察者
var o1 = new Observer1();
var o2 = new Observer2();
var o3 = new Observer3();

// 注册观察者
downloader.AddObserver(o1);
downloader.AddObserver(o2);
downloader.AddObserver(o3);

// 下载
downloader.Download();

创建一个被观察者对象,然后为其注册三个观察者。注册成功后,就可以执行下载文件的动作了。
当文件下载完成后,Download方法内部会自行通知已经成功注册的观察者们。

运行结果

程序运行结果

如你所见,当文件下载完成的通知发出后,各个观察者就开始了它们各自的小动作,分别是备份,压缩,转发。

总结

由于观察者们本身就有一个公共的抽象观察者,这样在某个观察者需要变动时,大可以废弃掉这个观察者,另起一个新的观察者,而不用去对现有的任何观察着做任何改动。因此从这个角度上讲,观察者模式是符合开闭原则的。
以上就是极简版的观察者模式的全部内容了。


什么么么么
382 声望4 粉丝