观察者模式

1.定义

  定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

2.类型:行为类模式

3.类图

  在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。比如,我们要设计一个右键菜单的功能,只要在软件的有效区域内点击鼠标右键,就会弹出一个菜单;再比如,我们要设计一个自动部署的功能,就像eclipse开发时,只要修改了文件,eclipse就会自动将修改的文件部署到服务器中。这两个功能有一个相似的地方,那就是一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。其实,能够实现这一点的方案很多,但是,无疑使用观察者模式是一个主流的选择。

  

4.代码示例

  观察者模式的结构

  • 被观察者(Subject):从类图中可以看到,类中有一个用来存放观察者对象的list容器,这个Vector容器是被观察者类的核心,另外还有三个方法:attach方法是向这个容器中添加观察者对象;detach方法是从容器中移除观察者对象;notify方法是依次调用观察者对象的对应方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多。
import abc


class Subject:
    """
    Know its observers. Any number of Observer objects may observe a
    subject.
    Send a notification to its observers when its state changes.
    """

    def __init__(self):
        self._observers = set()
        self._subject_state = None

    def attach(self, observer):
        observer._subject = self
        self._observers.add(observer)

    def detach(self, observer):
        observer._subject = None
        self._observers.discard(observer)

    def _notify(self):
        for observer in self._observers:
            observer.update(self._subject_state)

    @property
    def subject_state(self):
        return self._subject_state

    @subject_state.setter
    def subject_state(self, arg):
        self._subject_state = arg
        self._notify()
View Code
  • 观察者:观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用。
class Observer(metaclass=abc.ABCMeta):
    """
    Define an updating interface for objects that should be notified of
    changes in a subject.
    """

    def __init__(self):
        self._subject = None
        self._observer_state = None

    @abc.abstractmethod
    def update(self, arg):
        pass
  • 具体的观察者:观察者接口的具体实现,在这个角色中,将定义被观察者对象状态发生变化时所要处理的逻辑。
class ConcreteObserver(Observer):
    """
    Implement the Observer updating interface to keep its state
    consistent with the subject's.
    Store state that should stay consistent with the subject's.
    """

    def update(self, arg):
        self._observer_state = arg
        # ...

  主程序测试:

def main():
    subject = Subject()
    concrete_observer = ConcreteObserver()
    subject.attach(concrete_observer)
    subject.subject_state = 123


if __name__ == "__main__":
    main()

5.优缺点 

  观察者与被观察者之间是属于轻度的关联关系,并且是抽象耦合的,这样,对于两者来说都比较容易进行扩展。

       观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。

6.实例

class Publisher:  # 发布者
    def __init__(self):
        self.observers = []  # 接受传递进来的observer

    def add(self,observer):  # 添加一个新的观察者
        if observer not in self.observers:
            self.observers.append(observer)
        else:
            print('Failed to add:{}'.format(observer))

    def remove(self,observer):  # 删除一个观察者
        try:
            self.observers.remove(observer)
        except ValueError:
            print('Failed to remove:{}'.format(observer))

    def notify(self): # 发生变化时,通知所有观察者
        [o.notify(self) for o in self.observers]


class DefaultFormatter(Publisher):  # 默认格式
    def __init__(self,name):
        Publisher.__init__(self)
        self.name = name
        self._data = 0

    def __str__(self):  # type(self).__name__ 拿到对象的类名
        return "{}:'{}' has data={}".format(type(self).__name__,self.name,self._data)

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self,new_value):
        try:
            self._data = int(new_value)
        except ValueError as e:
            print("Error:{}".format(e))
        else:
            self.notify()  # try正常执行以后,会执行這个方法


class HexFormatter:
    def notify(self, publisher):
        print("{}:'{}' has now hex data = {}".format(type(self).__name__, publisher.name, hex(publisher.data)))


class BinartFormatter:
    def notify(self, publisher):
        print("{}:'{}' has now hex data = {}".format(type(self).__name__, publisher.name, bin(publisher.data)))


def main():
    df = DefaultFormatter('test1')  # 创建了test1实例
    print(df)
    print()

    hf = HexFormatter()
    df.add(hf)
    df.data = 3
    print(df)

    print()
    bf = BinartFormatter()
    df.add(bf)
    df.data = 21
    print(df)

    print()
    df.remove(hf)
    df.data = 40
    print(df)

    print()
    df.remove(hf)
    df.add(bf)

    df.data = 'hello'
    print(df)

    print()
    df.data = 15.8
    print(df)


if __name__ == '__main__':
    main()
数据格式化程序

 

  

posted @ 2017-07-07 17:27  看雪。  阅读(162)  评论(0编辑  收藏  举报