观察者模式 -- 发布-订阅模式

本文介绍了观察者模式的基本概念,通过示例代码展示了如何实现一对多的依赖关系,并讨论了其优势与不足。此外,还探讨了如何利用委托事件来改进模式的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 什么是观察者模式

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

2, 观察者模式的结构图

using System;
using System.Collections.Generic;
using System.Text;

namespace 观察者模式
{
    class Program
    {
        static void Main(string[] args)
        {
            //老板胡汉三
            Boss huhansan = new Boss();

            //看股票的同事
            StockObserver tongshi1 = new StockObserver("魏关姹", huhansan);
            //看NBA的同事
            NBAObserver tongshi2 = new NBAObserver("易管查", huhansan);

            huhansan.Attach(tongshi1);
            huhansan.Attach(tongshi2);

            huhansan.Detach(tongshi1);

            //老板回来
            huhansan.SubjectState = "我胡汉三回来了!";
            //发出通知
            huhansan.Notify();

            Console.Read();
        }
    }

    //通知者接口
    interface Subject
    {
        void Attach(Observer observer);
        void Detach(Observer observer);
        void Notify();
        string SubjectState
        {
            get;
            set;
        }
    }

    class Secretary : Subject
    {
        //同事列表
        private IList<Observer> observers = new List<Observer>();
        private string action;

        //增加
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        //减少
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        //通知
        public void Notify()
        {
            foreach (Observer o in observers)
                o.Update();
        }

        //前台状态
        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }

    class Boss : Subject
    {
        //同事列表
        private IList<Observer> observers = new List<Observer>();
        private string action;

        //增加
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        //减少
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        //通知
        public void Notify()
        {
            foreach (Observer o in observers)
                o.Update();
        }

        //老板状态
        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }

    //抽象观察者
    abstract class Observer
    {
        protected string name;
        protected Subject sub;

        public Observer(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        public abstract void Update();
    }

    //看股票的同事
    class StockObserver : Observer
    {
        public StockObserver(string name, Subject sub)
            : base(name, sub)
        {
        }

        public override void Update()
        {
            Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SubjectState, name);
        }
    }

    //看NBA的同事
    class NBAObserver : Observer
    {
        public NBAObserver(string name, Subject sub)
            : base(name, sub)
        {
        }

        public override void Update()
        {
            Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SubjectState, name);
        }
    }
}

3. 使用观察者模式的优势

将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使得各类紧密耦合,这样会给维护、扩展和重用都带来不便。而观察者模式的关键对象是主题subject和观察者observer ,一个subject可以有任意数目依赖它的observer,一旦subject的状态发生了改变,所有的observer都可以得到通知。subject发出通知时并不需要知道谁是它的观察者,也就是说,具体的观察者是谁,它不需要知道。而任何一个具体的观察者也不需要知道其他观察者的存在。

总的来讲,观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖与具体,从而使得各自的变化都不会影响令一边的变化(依赖倒转原则的绝佳体现)。

4. 观察者模式的应用范围

当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象等待改变时,应该考虑使用观察者模式。另外,当一个抽象模型有两个方面,其中一方面依赖另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

5.观察者模式的不足

尽管已经使用了依赖倒转原则,但“抽象通知者“还是依赖于”抽象观察者“,也就是说,一旦没有了抽象观察者这样的接口(如对已经封装好的类进行二次开发,而又不想破环程序本身的封装),通知的功能就不能完成;另外,如果通知者绑定了多个观察者,这些观察者更新自身状态的函数可能并不同名,此时也不能使用观察者模式。

6. 委托事件

为了弥补上述不足,可以使用事件委托。

委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的”类“,委托的实例将代表一个具体的函数。

一个委托可以搭载多个方法,所有方法将被依次唤起。更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类。也就是说,本来在subject类中增加或减少的抽象观察者集合以及通知时遍历的抽象观察者都不必要了。转到客户端来让委托搭载多个方法, 这就解决了本来与抽象观察者的耦合问题。

但委托也是有前提的,那就是委托对象所搭载的所有方法必须具有相同的原型和形式,也就是拥有相同的参数列表和返回值类型。

7. C++与事件委托

C++中没有委托机制,但我们可以使用boost::function对象或函数指针 自己进行封装。

https://www.cnblogs.com/cappuccino/p/3262056.html

https://blog.youkuaiyun.com/cyxisgreat/article/details/7506672

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值