设计模式:三.观察者模式

观察者模式是经常用到的设计模式,是行为模式的一种。他也经常和委托事件混在一起,但是就像程序代码是从上往下执行的,是先有观察者模式?再有委托?还是先有委托?再有观察者模式?很显然,当我们先学委托的时候,认真学过几次,发现怎么也学不太懂,是我们理解不行?还是说我们学习顺序搞错了?就如同上篇抽象工厂模式中为规避swich或者if else语句不符合开闭原则而使用反射一样。之后可能也会有委托和反射的笔记。


观察者模式(Observer Mode)

  1. 意图:当完全遵照单一职责原则将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而是而使各类紧密耦合,这样会给维护,扩展和重用都带来不便。于是观察者模式就派上用场了。

  2. 如何使用:当对象存在一对多关系时,让多个对象监听一个主题对象,当主题状态发生改变时,会通知所有它的依赖对象。

  3. 定义:定义一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。

  4. UML图
    这里写图片描述

  5. 关键代码

    abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();
        //增加观察者
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }
        //移除观察者
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }
        //通知
        public void Notify()
        {
            foreach (Observer o in observers)
            {
                o.Update();
            }
        }
    }
    
  6. 实例
    大话设计模式上的例子:

 public class ObserverModeCommon:MonoBehaviour
{
   private void Start()
    {
        ConcreteSubject s = new ConcreteSubject();
        s.Attach(new ConcreteObserver(s,"X"));
        s.Attach(new ConcreteObserver(s,"Y"));
        s.Attach(new ConcreteObserver(s,"Z"));
        s.SubjectState = "ABC";
        s.Notify();
    }
}
abstract class Subject
{
   private IList<Observer> observers = new List<Observer>();
    //增加观察者
    public void Attach(Observer observer)
    {
        observers.Add(observer);
    }
    //移除观察者
    public void Detach(Observer observer)
    {
        observers.Remove(observer);
    }
    //通知
    public void Notify()
    {
        foreach (Observer o in observers)
        {
            o.Update();
        }
    }
}
//具体观察者
class ConcreteObserver : Observer
{
    private string name;
    private string observerState;
    private ConcreteSubject subject;
    public ConcreteObserver(ConcreteSubject subject,string name)
    {
        this.subject = subject;
        this.name = name;
    }
    public override void Update()
    {
        observerState = subject.SubjectState;
        Debug.LogFormat("观察者{0}的新状态是{1}",name,observerState);
    }
    public ConcreteSubject Subject
    {
        get { return subject; }
        set { subject = value; }
    }

}
//具体主题
class ConcreteSubject:Subject 
{
    private string subjectState;
    //具体被观察者状态
    public string SubjectState
    {
        get { return subjectState; }
        set { subjectState = value; }
    }

}
//抽象观察者
abstract class Observer
{
    public abstract void Update();
}

这个例子的UML图就是上面通用模板的UML图。


观察者模式有个非常明显的缺点,如果你要更新一个已经封装好的组件时,因为这些组件早已被其他开发者给封装了,你是没办法给这个源码的对象上实现一个Observer接口的,但是水平高的程序员都会预留下更新状态的接口,但是这些状态的更新方法名字不一定就是Update,所以你就没办法遍历更新了。
这里就引入了委托。委托就是一种引用方法的类型。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。一旦委托分配了方法,委托将与该方法具有完全相同的行为。而且,一个委托可以搭载多个方法,所有方法被依次唤起。可以搭载返回值类型,参数类型相同的所有类,而不用在意他的方法名字和参数名字。而且这些方法可以不需要属于同一个类。也就是委托对象所搭载的所有方法必须具有相同的原型和形式,也就是拥有相同的参数列表和返回值类型。
其实多播委托声明时返回值都默认是void,否则返回值不知道应该送回什么地方。如果不将委托的声明返回void,则返回值返回的是最后一个链入委托链的方法的返回值,编译不会出错,但没有意义。
例子:


public class ObserverModeBook : MonoBehaviour
{
    void Start()
    {
        //老板胡汉三
        Boss huhansan = new Boss();
        //看股票的同事
        StockObserver tongshi1 = new StockObserver("小魏",huhansan );
        //看NBA的同事
        NBAObserver tongshi2 = new NBAObserver("小易",huhansan);
        //
        huhansan.Update += new EventHandler(tongshi1.CloseStockMarket);
        huhansan.Update += new EventHandler(tongshi2.CloseNBADirectSeeding);
        //老板回来
        huhansan.SubjectState = "我胡汉三回来了";
        huhansan.Notify();
    }
    private void Huhansan_Update()
    {
        throw new System.NotImplementedException();
    }
}
//增加了抽象的观察者
public abstract class Observers
{
    protected string name;
    protected Subjects sub;
    public Observers(string name, Subjects sub)
    {
        this.name = name;
        this.sub = sub;
    }
    public abstract void Update();
}

//看股票的同事
class StockObserver
{
    private string name;
    private Subjects sub;
    public StockObserver(string name,Subjects sub)
    {
        this.name = name;
        this.sub = sub;
    }
    //关闭股票行情
    public void CloseStockMarket()
    {
        Debug.LogFormat("{0}{1}关闭股票行情,继续工作!",sub.SubjectState,name);
    }
}
//看NBA的同事
class NBAObserver
{
    private string name;
    private Subjects sub;
    public NBAObserver(string name, Subjects sub)
    {
        this.name = name;
        this.sub = sub;
    }
    //关闭NBA直播
    public void CloseNBADirectSeeding()
    {
        Debug.LogFormat("{0}{1}关闭NBA直播,继续工作!",sub.SubjectState,name);
    }
}
public delegate void EventHandler();//声明一个委托
public class Boss : Subjects
{
    //同事列表
    public event EventHandler Update;
    private IList<Observers> observers = new List<Observers>();
    private string Action;
    //老板状态
    public string SubjectState
    {
        get { return Action; }
        set { Action = value; }
    }
    //增加
    public void Attach(Observers observer)
    {
        observers.Add(observer);
    }
    //减少
    public void Detach(Observers observer)
    {
        observers.Remove(observer);
    }
    //通知
    public void Notify()
    {
        Update();
    }
}
//通知者接口
public interface Subjects
{
    void Notify();
    string SubjectState { get; set; }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值