设计模式(二十)—— 观察者模式

模式简介


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

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

结构分析


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

程序输出

适用场景


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

  • 当一个对象必须通知其他对象,而它不知道其他对象是谁。
  • 但一个抽象模型有两个方面,其中一个方面依赖于另一个方法。将二者封装在独立的对象中以使它们各自独立地改变和重用。

posted @ 2018-07-13 16:37 Answer.Geng 阅读(...) 评论(...) 编辑 收藏