zoukankan      html  css  js  c++  java
  • 观察者模式(Observer Pattern)

    一、概述
    在软件设计工作中会存在对象之间的依赖关系,当某一对象发生变化时,所有依赖它的对象都需要得到通知。如果设计的不好,很容易造成对象之间的耦合度太高,难以应对变化。使用观察者模式可以降低对象之间的依赖,以松耦合的方式实现这一目标。


    二、观察者模式
    观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。其结构图如下:

    Subject知道它的所有观察者并提供了观察者注册和删除订阅的接口。
    Observer为那些在目标发生改变时需获得通知的对象定义一个更新接口。
    ConcreteSubject实现Subject接口,当改变状态时向依赖于它的ConcreteObserver发送通知。
    ConcreteObserver实现Observer的更新接口,使得自身能根据ConcreteSubject状态的不同而做出相应的改变。
    观察者模式分为推模式和拉模式两种。推模式是当有通知时,把依赖对象的信息以参数的形式传递给所有观察者,而拉模式通知方法本身并不带任何的参数,是由观察者自己到依赖对象那里取回相关信息。在推模式下,所有观察者都通过参数传递的方式得到依赖对象的全部信息,与依赖对象之间的耦合较低,但不能实现“按需所取”所需要信息的。而拉模式仅仅是通知观察者,至于要不要提取依赖对象的信息则是观察者自己的事情,这么一来就实现“按需所取”,但往往要在ConcreteObserver里保存一个ConcreteSubject的引用,与ConcreteSubject的耦合也加强了。
    观察者模式的Subject一般需要提供观察者注册和删除订阅的接口,但在.NET中,往往可以利用事件和委托的特性来实现观察者模式,这是一种更为优雅的方案。

    三、示例
    我们现在利用事件实现观察者模式。我们设计一个信用卡消费的简单例子,在消费的同时需要对用户账户进行扣款,同时对用户进行短信提醒。
    首先定义信用卡类,当消费金额变动时会触发Notify方法通知该对象的所有观察者。

    public class CreditCard : EventArgs
        {
            private float _spendAmount;
            public event EventHandler<CreditCard> SpendMoney;
    
            public float SpendAmount
            {
                get
                {
                    return _spendAmount;
                }
                set
                {
                    _spendAmount = value;
                    Notify();
                }
            }
    
            private void Notify()
            {
                if (SpendMoney != null)
                {
                    SpendMoney(this, this);
                }
            }
        }

    接着定义Observer接口,并使用户帐户类和短信提醒类实现这个接口,其中这两个ConcreteObserver类的Update方法签名必须与CreditCard中的事件SendMoney一致,否则就无法注册到CreditCard。

    public interface IObserver<T>
        {
            void Update(Object sender, T e);
        }
    
        public class SMSNotify : IObserver<CreditCard>
        {
            public void Update(Object sender, CreditCard e)
            {
                Console.WriteLine("Sms notify.Spend {0}", e.SpendAmount);
            }
        }
    
        public class Account : IObserver<CreditCard>
        {
            private float _accountAmount;
    
            public Account(float accountAmount)
            {
                _accountAmount = accountAmount;
            }
    
            public void Update(Object sender, CreditCard e)
            {
                _accountAmount += e.SpendAmount;
                Console.WriteLine("Account amount is {0}", _accountAmount);
            }
        }

    最后看一下客户端调用。

    static void Main(string[] args)
        {
            CreditCard creditCard = new CreditCard();
            SMSNotify sms = new SMSNotify();
            Account account = new Account(1000);
            creditCard.SpendMoney += account.Update;
            creditCard.SpendMoney += sms.Update;
            creditCard.SpendAmount = 200;
        }
  • 相关阅读:
    剑指offer编程题Java实现——面试题14调整数组顺序使奇数位于偶数之前
    剑指offer编程题Java实现——面试题13在O(1)时间内删除链表节点
    剑指offer编程题Java实现——面试题12相关题大数的加法、减法、乘法问题的实现
    剑指offer编程题Java实现——面试题12打印1到最大的n位数
    《深入理解JAVA虚拟机》——学习笔记
    剑指offer编程题Java实现——面试题11数值的整数次方
    剑指offer编程题Java实现——面试题10二进制中1的个数
    剑指offer编程题Java实现——面试题9斐波那契数列
    剑指offer编程题Java实现——面试题8旋转数组的最小数字
    mysql高可用集群——MHA架构
  • 原文地址:https://www.cnblogs.com/gzskys/p/5740954.html
Copyright © 2011-2022 走看看