【设计模式】从观察者模式到事件委托

引言
很久之前就接触过观察者模式,最近在项目开发中,发现C#从语言层面上新增了event关键字,一时理不清观察者模式和委托之前的关系。通过《大话设计模式》和《游戏编程模式》重新复习理解一下如何从观察者模式过度到事件委托机制。
观察者模式
定义
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
作用
● 观察者模式最大的意义在于解耦和,可以让耦合的双方依赖于抽象,而不是依赖于具体。
● 如果经常需要为了理解程序的逻辑而去梳理模块之间的调用顺序,那么就不要用观察者模式来表达这种顺序执行链,可以考虑其他方法。
● 观察者模式非常适合于一些不相关的模块之间的通信问题,不适合于单个紧凑的模块内部通信。
代码

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ObserverClass : MonoBehaviour {

    abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();
        public void Attach(Observer ob)
        {
            observers.Add(ob);
        }

        public void Detach(Observer ob)
        {
            observers.Remove(ob);
        }

        public void Notify()
        {
            foreach(Observer ob in observers)
            {
                ob.Update();
            }
        }

    }

    abstract class Observer
    {
        public abstract void Update();
    }

    class ConcreteSubject : Subject
    {
        private string subjectState;
        public string SubjectState
        {
            get { return subjectState; }
            set { subjectState = value; }
        }
    }

    class ConcreteObserver:Observer
    {
        private string name;
        private string observerState;
        private ConcreteSubject sub;

        public ConcreteObserver(ConcreteSubject sub, string name)
        {
            this.sub = sub;
            this.name = name;
        }

        public override void Update()
        {
            observerState = sub.SubjectState;
            Debug.Log("观察者" + name + "的新状态是" + observerState);
        }

        public ConcreteSubject Subject
        {
            get { return sub; }
            set { sub = value; }
        }
    }

    void Start()
    {
        ConcreteSubject sub = new ConcreteSubject();

        sub.Attach(new ConcreteObserver(sub, "X"));
        sub.Attach(new ConcreteObserver(sub, "Y"));
        sub.Attach(new ConcreteObserver(sub, "Z"));

        sub.SubjectState = "ABC";
        sub.Notify();


    }
}

运行结果
这里写图片描述

上述示例改进方向
虽然上述实现通过抽象来实现,然而抽象通知者还是依赖抽象观察者。以下两种情况,抽象的观察者模式并不好实现:
1. 如果没有了抽象观察者这样的接口,就无法实现通知观察对象的功能。
2. 如果每个观察者需要调用的更新方法不同,也无法通过抽象的观察者模式实现。
事件委托
● 委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
● 一旦为委托分配了方法,委托将与该方法具有完全相同的行为。而且,一个委托可以搭载多个方法,所有方法被依次唤起。
● 委托对象所搭载的所有方法必须具有相同的原型和形式,也就是拥有相同的参数列表和返回值类型。
解决了上述示例的不足
委托对象所搭载的方法并不需要属于同一个类。
代码

using UnityEngine;
using System.Collections;

public class DelegateClass : MonoBehaviour {

    interface Subject
    {
        void Notify();
        string SubjectState
        {
            get;
            set;
        }
    }
    class Observer1
    {
        private string name;
        private Subject sub;

        public Observer1(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        public void Operate1()
        {
            Debug.Log(sub.SubjectState + name + " Operate1!" );
        }
    }

    class Observer2
    {
        private string name;
        private Subject sub;

        public Observer2(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        public void Operate2()
        {
            Debug.Log(sub.SubjectState + name + " Operate2!");
        }
    }

    class ConcreteSub : Subject
    {
        public delegate void EventHandler();
        public event EventHandler Update;               //声明一个"EventHandler(事件处理程序)"的委托事件,名称叫做"Update"

        private string action;

        public void Notify()
        {
            Update();
        }

        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }

    void Start () 
    {
        ConcreteSub sub = new ConcreteSub();

        Observer1 ob1 = new Observer1("ob1", sub);
        Observer2 ob2 = new Observer2("ob2", sub);

        sub.Update += new ConcreteSub.EventHandler(ob1.Operate1);           //将两个不同类的不同方法委托给了同一个Subject对象
        sub.Update += new ConcreteSub.EventHandler(ob2.Operate2);

        sub.SubjectState = "Trigger Notify!";
        sub.Notify();
    }

}

运行结果
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值