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();
        }
    }
    

    程序输出

    适用场景


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

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

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

  • 相关阅读:
    Sql2008 全文索引 简明教程
    sql server 全文检索 使用
    数据库分词查询的优缺点以及英文和中文各自的分词方法(一)
    win10中打开SQL Server配置管理器方法
    Asp.net 中高亮显示搜索关键字简单方法
    EntityFramework优缺点
    LoadXml载入Xhtml文件速度很慢
    c#无限循环线程如何正确退出
    线程的等待方法:join
    C#如何优雅的结束一个线程
  • 原文地址:https://www.cnblogs.com/Answer-Geng/p/9305523.html
Copyright © 2011-2022 走看看