Event Pattern(也称为Event Notification Pattern)是Observer Pattern的一个变种。.NET CLR的eventdelegate就是该模式的一个典型的实例。本文将介绍下该模式及其实现。
   Observer Pattern有Push和Pull两种类型。Push就是在通知Observer的时候同时传递数据。而和Push相反的Pull则是要求在通知后Observer从Subject中查询数据。说句大白话就是:Push比较厚道,在通知的时候顺便告诉你结果;而Pull则是故弄玄虚,告诉你有现在结果了,具体是什么结果你就来问吧。话虽这么说,但实际应用中Push和Pull各有利弊,因此都有一定的应用。在Event Pattern就使用Push模式,数据通过EventArgs传递。较之Observer PatternEvent Pattern有如下几个特点:
1 注册时候Obsever Pattern需要使用Observer实例的引用,而Event Pattern则是使用一个方法作为EventHandler。打个比方,如果假设你是一个Observer,在Obsever Pattern中你得把自己全给搭上(Subject保有对你的引用),而Event Pattern就只是需要你的一个联系方式(EventSource只是保有你的其中一个方法的地址)。
2 Obsever Pattern中Subject依赖于Observer的接口,而Event Pattern中仅仅是依赖一个Delegate。
该模式实现的UML图如下:
IronPython系列:Event Pattern及其实现_Event Pattern
   其中,EventHook负责EventHandler的注册以及事件的触发。EventSource利用EventHook来实现在属性改变的时候发布通知。EventSubscriber通过定义一个符合EventHandler声明的方法作为事件处理函数。该设计的IronPython的代码实现如下:
class EventHook(object):
        def __init__(self):
                self.__handlers = []
        def __iadd__(self, handler):
                self.__handlers.append(handler)
                return self
        def __isub__(self, handler):
                self.__handlers.remove(handler)
                return self
        def fire(self, *args, **keywargs):
                for handler in self.__handlers:
                        handler(*args, **keywargs)

class EventSource(object):
        def __init__(self, value):
                self.modified = EventHook()
                self.__value = value

        def changeValue(self, value):
                if self.__value != value:
                     oldValue = self.__value
                     self.__value = value
                     self.modified.fire(value, oldValue, type = "ChangeValue")

class EventSubscriber(object):
        def __init__(self, name):
                self.__name = name

        def handler(self, *args, **keywargs):
                print self.__name + " got: " + str(args) + str(keywargs)

if __name__ == "__main__":
        data = EventSource(10)
        console = EventSubscriber("Cosole")
        graphic = EventSubscriber("Graphic")
        data.modified += console.handler
        data.modified += graphic.handler
        print "Source change value to 20"
        data.changeValue(20)
        print "Source is still 20"
        data.changeValue(20)

   运行结果如下:
IronPython系列:Event Pattern及其实现_Event Pattern_02
   从中可以看到,如果通过数据data的changeValue()接口改变了值,console和graphic都可以收到通知;而如果调用了数据data的changeValue()接口但值没有改变,console和graphic就不会得到消息。