zoukankan      html  css  js  c++  java
  • 设计模式(二十)—— 观察者模式

    模式简介


    定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并更新。

    观察者模式又叫发布-订阅模式,主要描述了一种目标与观察者之间的相互关系。目标对象一旦发生变化,它所有的观察者都得到通知并作出相应的更新操作。下图恰好描述了这种场景,目标对象拿出烟,观察者纷纷掏出火柴帮忙点烟。

    结构分析


    UML类图

    角色说明

    • Subject

    目标类。提供删除、添加观察者的方法,当它的状态发生变化时,向它的观察者发出通知。

    • Observer

    观察者。为具体观察者提供一个统一的更新接口。

    • ConcreteObserver

    具体观察者。实现更新接口,使自身状态与目标一致。

    工作原理

    当目标对象发生改变时,它将通知所有观察者,观察者得到通知后访问目标对象更新状态。

    结构代码

    //目标类
    public class Subject
    {
        private List<Observer> _observers = new List<Observer>();
        private int _state;
        public int GetState()
        {
            return _state;
        }
    
        public void SetState(int state)
        {
            _state = state;
            Notify();
        }
        public void Attach(Observer observer)
        {
            if (!_observers.Contains(observer))
            {
                _observers.Add(observer);
            }
        }
    
        public void Detach(Observer observer)
        {
            if (_observers.Contains(observer))
            {
                _observers.Remove(observer);
            }
        }
    
        public void Notify()
        {
            foreach (var observer in _observers)
            {
                observer.Update();
            }
        }
    }
    
    //观察者
    public abstract class Observer
    {
        protected Subject _subject;
        public abstract void Update();
    }
    
    //具体观察者A
    public class ConcreteObserverA : Observer
    {
        public ConcreteObserverA(Subject subject)
        {
            _subject = subject;
            subject.Attach(this);
        }
        public override void Update()
        {
            Console.WriteLine($"ConcreteObserverA Update State:{_subject.GetState()}");
        }
    }
    
    //具体观察者B
    public class ConcreteObserverB : Observer
    {
        public ConcreteObserverB(Subject subject)
        {
            _subject = subject;
            subject.Attach(this);
        }
        public override void Update()
        {
            Console.WriteLine($"ConcreteObserverB Update State:{_subject.GetState()}");
        }
    }
    
    //具体观察者C
    public class ConcreteObserverC : Observer
    {
        public ConcreteObserverC(Subject subject)
        {
            _subject = subject;
            subject.Attach(this);
        }
        public override void Update()
        {
            Console.WriteLine($"ConcreteObserverC Update State:{_subject.GetState()}");
        }
    }
    
    //客户端调用
    class Program
    {
        static void Main(string[] args)
        {
            Subject subject = new Subject();
            ConcreteObserverA a = new ConcreteObserverA(subject);
            ConcreteObserverB b = new ConcreteObserverB(subject);
            ConcreteObserverC c = new ConcreteObserverC(subject);
    
            subject.SetState(200);
            Console.ReadLine();
        }
    }
    

    程序输出

    示例分析


    本节模拟开篇描述的场景,女演员(目标对象)拿出烟,男演员(观察者)为其点烟。首先创建女演员类,包含一个Observer集合用来保存观察者,使用_state字段模拟女演员状态的变化,提供SetState以及GetState存取该状态,并提供Attach和Detach方法添加或删除观察者。

    public class Actress
    {
        private List<Observer> _observers = new List<Observer>();
        private int _state;
        public int GetState()
        {
            return _state;
        }
        public void SetState(int state)
        {
            _state = state;
            Notify();
        }
        public void Notify()
        {
            foreach (var observer in _observers)
            {
                observer.LightCigarette();
            }
        }
        public void Attach(Observer observer)
        {
            if (!_observers.Contains(observer))
            {
                _observers.Add(observer);
            }
        }
        public void Detach(Observer observer)
        {
            if (_observers.Contains(observer))
            {
                _observers.Remove(observer);
            }
        }
    }
    

    创建观察者,分别实现3个具体观察者。

    public abstract class Observer
    {
        protected Actress _actress;
        public abstract void LightCigarette();
    }
    
    public class ActorA : Observer
    {
        public ActorA(Actress actress)
        {
            _actress = actress;
            actress.Attach(this);
        }
        public override void LightCigarette()
        {
            Console.WriteLine($"ActorA light the cigarette");
        }
    }
    
    public class ActorB : Observer
    {
        public ActorB(Actress actress)
        {
            _actress = actress;
            actress.Attach(this);
        }
        public override void LightCigarette()
        {
            Console.WriteLine($"ActorB light the cigarette");
        }
    }
    
    public class ActorC : Observer
    {
        public ActorC(Actress actress)
        {
            _actress = actress;
            actress.Attach(this);
        }
        public override void LightCigarette()
        {
            Console.WriteLine($"ActorC light the cigarette");
        }
    }
    

    客户端调用

    class Program
    {
        static void Main(string[] args)
        {
            Actress actress = new Actress();
            ActorA a = new ActorA(actress);
            ActorB b = new ActorB(actress);
            ActorC c = new ActorC(actress);
    
            actress.SetState(1);
            Console.ReadLine();
        }
    }
    

    程序输出

    适用场景


    • 当一个对象的改变需要同时改变其它对象,而又不知道具体有多少对象时。

    • 当一个对象必须通知其他对象,而它不知道其他对象是谁。

    • 但一个抽象模型有两个方面,其中一个方面依赖于另一个方法。将二者封装在独立的对象中以使它们各自独立地改变和重用。

  • 相关阅读:
    让Div居中的方法
    创建对象的几种方式
    [Gport]2014移动互联网趋势——100名CEO的一句话解读
    专访腾讯云陈磊:微信云助力企业转型把握O2O时代价值
    Head First Python 学习笔记(第二章:分享你的代码)
    Head First Python 学习笔记(第一章:使用IDLE来帮助学习Python)
    《写给大家看的设计书》学习笔记
    用TreeView以递归显示选择磁盘上文件夹中全部文件夹和文件
    WebBrowser实现:自动填充网页上的用户名和密码并点击登录按钮
    C#调用免费天气预报WebService
  • 原文地址:https://www.cnblogs.com/Answer-Geng/p/9305523.html
Copyright © 2011-2022 走看看