设计模式(20) 观察者模式

观察者模式是一种平时接触较多的模式。它主要用于一对多的通知发布机制,当一个对象发生改变时自动通知其他对象,其他对象便做出相应的反应,同时保证了被观察对象与观察对象之间没有直接的依赖。

GOF对观察者模式的描述为:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically..
— Design Patterns : Elements of Reusable Object-Oriented Software

观察者模式的适用场景

  • 当存在一类对象通知关系上依赖于另一类对象的时候,把它们进行抽象,确保两类对象的具体实现都可以相对独立的变化,但它们交互的接口保持稳定。
  • 一个类型状态变化时,需要通知的对象的数量不固定,会有增加或删除若干被通知对象的情况。
  • 需要让目标对象与被通知对象之间保持松散耦合的时间。

UML类图如下:

代码实例

public interface IObserver<T>
{
    void Update(SubjectBase<T> subject);
}

public abstract class SubjectBase<T>
{
    protected IList<IObserver<T>> observers = new List<IObserver<T>>();

    protected T state;
    public virtual T State
    {
        get { return state; }
    }

    //Attach
    public static SubjectBase<T> operator +(SubjectBase<T> subject, IObserver<T> observer)
    {
        subject.observers.Add(observer);
        return subject;
    }

    //Detach
    public static SubjectBase<T> operator -(SubjectBase<T> subject, IObserver<T> observer)
    {
        subject.observers.Remove(observer);
        return subject;
    }

    //更新各观察者
    public virtual void Notify()
    {
        foreach (var observer in observers)
        {
            observer.Update(this);
        }
    }

    public virtual void Update(T state)
    {
        this.state = state;
        Notify();//触发对外通知
    }
}

public class Subject<T> : SubjectBase<T> { }

public class Observer<T> : IObserver<T>
{
    public T State;
    public void Update(SubjectBase<T> subject)
    {
        this.State = subject.State;
    }
}

调用端

static void Main(string[] args)
{
    SubjectBase<int> subject = new Subject<int>();
    Observer<int> observer1 = new Observer<int>();
    observer1.State = 10;
    Observer<int> observer2 = new Observer<int>();
    observer2.State = 20;
    subject += observer1;
    subject += observer2;
    subject.Update(30);
    Console.WriteLine($"ob1:{observer1.State}  ob2:{observer2.State}");
    //ob1:30 ob2:30 两个观察者都发生了变化
    subject -= observer2;
    subject.Update(40);
    Console.WriteLine($"ob1:{observer1.State}  ob2:{observer2.State}");
    //ob1:40 ob2:30 observer2被移除,不会跟随变化
}

这里的被观察者继承基类SubjectBase,观察者实现接口IObserver。SubjectBase和IObserver相互依赖,SubjectBase本身不知道会有哪些具体IObserver类型希望获得它的更新通知,具体的Observer类型也并不需要关心目标类型,只需要依赖SubjectcBase,所以实际上一个观察者可以跟踪多个被观察者。

推模式和拉模式

根据当目标对象状态更新的时候,观察者更新自己数据的方式,可以将观察者模式分为推模式和拉模式。

  • 推模式:目标对象在通知里把需要更新的信息作为参数提供给IObserver的Update()方法。采用这种方式,观察者只能只能被动接受,如果推送的内容比较多,那么对网络、内存或者I/O的开销就会很大。

  • 拉模式:目标对象仅仅告诉观察者有新的状态,至于该状态是什么,则需要观察者主动访问目标对象来获取。这种方式下,观察者获取信息的时机和内容都可以自主决定,但如果观察者没有及时获取信息,就会漏掉之前通知的内容。

前面的代码示例是两种方式的结合,看起来像是推模式,但他推送的是一个SubjectBase的引用,观察者可以根据需要通过这个引用访问到具体的状态,从这个角度看又是拉模式。

事件

.NET中的事件机制也可以看作观察者模式,事件所定义的委托类型本身就是个抽象的观察者,而且相对经典的观察者模式,事件更加简单、灵活,耦合也更加松散。
代码示例

public class UserEventArgs : EventArgs
{
    public string Name { get; }
    public UserEventArgs(string name)
    {
        this.Name = name;
    }
}

public class User
{
    public event EventHandler<UserEventArgs> NameChanged;
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NameChanged(this, new UserEventArgs(value));
        }
    }
}

观察者,注册事件

public class Test
{
    public static void Entry()
    {
        User user = new User();
        user.NameChanged += (sender, args) =>
        {
            Console.WriteLine(args.Name);
        };
        user.Name = "Andy";
    }
}

观察者模式的缺点

  • 如果观察者比较多,逐个通知会相对耗时。
  • 测试和调试相比直接依赖更加困难。
  • 可能导致内存泄漏,即使所有观察者都已经失效了,但如果它们没有注销对主题对象的观察,那么观察者和主题对象间的这种相互的引用关系,会使双方无法被GC回收。

参考书籍:
王翔著 《设计模式——基于C#的工程化实现及扩展》

(0)

相关推荐

  • 设计模式中的观察者模式

    观察者模式是一种软件设计模式,其中一个名为主体(Subject)的对象维护其依赖项列表,称为观察者,并通常通过调用它们(observers)的方法之一来自动通知它们任何状态更改. 观察者模式主要用于在 ...

  • 无废话设计模式(15)行为型模式--观察者模式

    0-前言 观察者模式定义:定义了一种一对多的依赖关系让多个观察者对象同事监听某一主题对象. 这个主题对象在状态发生改变时,会通知所有观察者对象,使他们能够自动更新自己: 1-实现 1-1.简单UML图 ...

  • 设计模式-行为型-观察者模式

    观察者模式(Observer): 指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 观察者模式的角色: 1)抽象目标(Subject):也叫抽象 ...

  • JavaScript设计模式之观察者模式

    目录 简介 实现 创建观察者对象 简介 观察者模式由称作发布-订阅者模式或消息机制,该模式定义一种依赖关系,旨在解决主体对象与观察者之间功能的耦合. 例如案例:想实现一个评论模块,当用户发送消息时,在 ...

  • PHP设计模式—观察者模式

    定义: 观察者模式(Observer):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 结构: Eve ...

  • 行为型模式之观察者模式

    在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变.例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心. 在软件世界也是这样,例如 ...

  • PHP设计模式之观察者模式

    PHP设计模式之观察者模式 观察者,貌似在很多科幻作品中都会有这个角色的出现.比如我很喜欢的一部美剧<危机边缘>,在这个剧集中,观察者不停的穿越时空记录着各种各样的人或事.但是,设计模式中 ...

  • [PHP小课堂]PHP设计模式之观察者模式

    [PHP小课堂]PHP设计模式之观察者模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 软件设计模式修炼 -- 观察者模式

    观察者模式是一种经常使用的设计模式,在软件系统中对象并不是孤立存在的,一个对象行为的改变可能会导致其他与之存在依赖关系的对象行为发生改变,观察者模式用于描述对象之间的依赖关系. 模式动机 很多情况下, ...

  • 图解Java设计模式之观察者模式

    天气预报项目需求 1)气象站可以将每天测量到的湿度.温度.气压等等以公告的形式发布出去(比如发布到自己的网站或第三方). 2)需要设计开放型API,便于其他第三方也能接入气象站获取数据. 3)提供温度 ...

  • JAVA设计模式之观察者模式

    JAVA设计模式之观察者模式

  • 设计模式之观察者模式(observer pattern)

    观察者模式主要用于处理对象间的一对多的关系,是一种对象行为模式.该模式的实际应用场景比较容易确认,当一个对象状态发生变化时,所有该对象的关注者均能收到状态变化通知,以进行相应的处理. 本文希望通过简单 ...

  • JAVA设计模式之观察者模式 - Observer

    有趣的事情发生时,可千万别错过了!有一个模式可以帮你的对象知悉现况,不会错过该对象感兴趣的事.对象甚至在运行时可决定是否要继续被通知.有了观察者,你将会消息灵通. 介绍 观察者模式的定义: 在对象之间 ...

  • 设计模式之观察者模式(三)

    又和大家见面了.首先,和大家说声抱歉,之前的几篇文章,可能条理清晰之类的做的不太好,每篇文章的篇幅也比较长,小编在收到读者的建议之后, 也是认真的思考了一番.之前的想法是尽量把一个模块介绍完,没想到一 ...