• 观察者模式


    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()
    数据格式化程序

      

  • 相关阅读:
    也URL Rewriter
    一窝蜂的分类信息
    再思考:分类信息的前途
    Ajax的一个体验:Ajax.NET A free library for the Microsoft .NET Framework
    EonerCMS——做一个仿桌面系统的CMS(十三)
    关于IE6、7、8下实现盒阴影的几个注意点
    EonerCMS——做一个仿桌面系统的CMS(十附最新源码)
    EonerCMS——做一个仿桌面系统的CMS(十一)
    用cloudzoom做一个仿淘宝的宝贝放大镜查看功能
    剑走偏锋——用css制作一个三角形箭头
  • 原文地址:https://www.cnblogs.com/vipchenwei/p/7133312.html
Copyright © 2020-2023  润新知