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()
- 观察者:观察者角色一般是一个接口,它只有一个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()