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

    1 GOF中的定义

    意图

    定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[GOF 《设计模式》]

    结构图

    2.概述

    个人感觉观察者模式定义的比较不容易理解:什么多个观察者关注某个主题的,这个模式解决的是当一个对象需要调用一系列对象的方法时,并且是被调用方自己注册自己是否被调用,调用方不知道要调用哪些方法的问题。

    3生活中的例子

    现在,银行业务中有一项,当账号金额发生变化时就进行通知,默认是通知到手机,也可以选择将信息同时发送到邮箱。

    4.调用方依赖被调用方

    情景1:在这个业务的起初,账号金额变化,通知到手机

    实现:

    View Code
        public class Account
        {
            public void AmountChange() 
            {
                Phone phone = new Phone();
                phone.Send();
            }
        }
    
        public class Phone
        {
            public void Send() 
            {
                Console.WriteLine("Send phone!");
            }
        }
            static void Main(string[] args)
            {
                Account account = new Account();
                account.AmountChange();    
            }

    说明:在这里,Account是调用方(即所谓的主题),Phone是被调用方(所谓的观察者)。在这里调用方强依赖被调用方。

    情景2:业务发展了,账号金额变化,即通知手机,也通知邮箱。

    实现:

    View Code
        public class Account
        {
            public void AmountChange()
            {
                Phone phone = new Phone();
                Email email = new Email();
                phone.Send();
                email.Send();
            }
        }
    
        public class Email
        {
            public void Send()
            {
                Console.WriteLine("Send Email!");
            }
        }
    
        public class Phone
        {
            public void Send()
            {
                Console.WriteLine("Send phone!");
            }
        }
    
            static void Main(string[] args)
            {
                Account account = new Account();
                account.AmountChange();
            }

    说明:在这里,新添加一个发送到邮箱的功能,必须要修改已有的Account类,违背了开放关闭原则。

    5.调用方依赖接口,被调用方依赖接口(按照合约的设计)

    情景3:重构情景2的代码

    实现:

    View Code
        public class Account
        {
            IList<IObserver> oList = new List<IObserver>();
    
            public void Attach(IObserver observer) 
            {
                oList.Add(observer);
            }
            public void AmountChange()
            {
                foreach (IObserver observer in oList)
                {
                    observer.SendNotify();
                }
            }
        }
    
        public interface IObserver
        {
            void SendNotify();
        }
    
        public class Phone : IObserver
        {
            public void SendNotify()
            {
                Console.WriteLine("Send phone!");
            }
        }
    
        public class Email:IObserver
        {
            public void SendNotify()
            {
                Console.WriteLine("Send Email!");
            }
        }
    
    static void Main(string[] args)
            {
                Account account = new Account();
                Email email = new Email();
                account.Attach(email);
                Phone phone = new Phone();
                account.Attach(phone);
    
                account.AmountChange();
            }

    说明:在这里,调用方维护一个被调用方的列表,当需要调用被调用方时,只需要循环这个列表,即可;当新添加观察者时,只需要添加一个类继承IObserver接口,然后在客户端注册到IObserver列表中即可;

    6.最后的重构(主动定阅)

    情景4:在情景3中的实现,被调用方注册到调用列表的操作是在客户代码中实现的,被调用方被动注册,而在定义中被调用方是否被调用,是由被调用方自身决定,而不是调用方来决定。

    实现:

    View Code
        public class Account
        {
            IList<IObserver> oList = new List<IObserver>();
    
            public void Attach(IObserver observer) 
            {
                oList.Add(observer);
            }
            public void AmountChange()
            {
                foreach (IObserver observer in oList)
                {
                    observer.SendNotify();
                }
            }
        }
    
        public interface IObserver
        {
            void SendNotify();
        }
    
        public class Phone : IObserver
        {
            public Account subject;
    
            public Phone() { }
    
            public Phone(Account subject) 
            {
                this.subject = subject;
                this.subject.Attach(this);
            }
            public void SendNotify()
            {
                Console.WriteLine("Send phone!");
            }
        }
    
        public class Email : IObserver
        {
            public Account subject;
    
            public Email() { }
            
            public Email(Account subject) 
            {
                this.subject = subject;
                this.subject.Attach(this);
            }
            public void SendNotify()
            {
                Console.WriteLine("Send Email!");
            }
        }
    
            static void Main(string[] args)
            {
                Account account = new Account();
    
                Email email = new Email();
                Phone phone = new Phone(account);
    
                account.AmountChange();
                return;
            }

    说明:在这里,被调用方是否被调用的决定决在被调用方;

    7.总结

    总的看来,Observer与Command十分相似,都是将行为抽象,让行为独立的变化。只不过在调用方是否调用被调用方的决定权有所不同,在Command中决定决在调用方,在Observer中决定权在被调用方。在Observer中,如果被调用的方法已在某个类实现,也可以像Command命令模式那样再融合下适配器模式,加入一个Receiver类。

  • 相关阅读:
    CSP201412-2:Z字形扫描
    CSP201409-2:画图
    CSP201403-2:窗口
    CSP201312-2:ISBN号码
    CSP201709-1:打酱油
    CSP201703-1:分蛋糕
    CSP201612-1:中间数
    LOAM笔记及A-LOAM源码阅读
    特征值、特征向量与PCA算法
    欧几里得与区域生长算法
  • 原文地址:https://www.cnblogs.com/dataadapter/p/2652327.html
Copyright © 2011-2022 走看看