一、观察者模式介绍
概念:
观察者模式(Observer Pattern),又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。定义了对象之间的一种一对多的依赖关系,从而使得当被观察对象状态发生变化时,自动通知其依赖对象,并且依赖对象自动更新。
解决重点:
被观察对象的状态改变如何主动通知其依赖的对象,同时需要考虑到低耦合和易用性,保证高度协作。
如何解决:
面向对象技术可以弱化这种依赖关系。抽象类中需要设置一个ArrayList存放所有的观察者。
优点:
1.目标对象和观察者对象是抽象耦合的;
2.建立了一套触发机制。
缺点:
1.观察者模式只是主动通知了目标对象发生了变化,没有相应的机制使得观察者知道所观察的目标对象如何发生变化的;
2.观察者和观察目标之间可能存在循环依赖,观察者模式中目标对象可能触发两者之间的循环调用,从而系统存在崩溃风险。
3.如果目标对象存在多个直接或间接的观察者对象,主动通知所有的观察者会消耗大量的资源,花费大量时间。
场景理解:
在众多游戏中,主角行走过程中,地图中心摄像头总是跟随主角调整视角和位置,使得主角总是处于场景的中心。主角进行行走或战斗操作时,主角的仆从根据主角的操作进行相应的跟随或战斗行为。
二、简单实现
观察者模式结构如图,其中角色包括Subject(目标对象)、ConcreteSubject(具体目标)、Observer(观察者)、ConcreteObserver(具体观察者)。
(模式图来源:https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html)
Python代码实现简单的观察者模式:
1 # *-* coding:utf-8 *-* 2 3 4 # Observer 5 class Bob_Observer(): 6 def save(self): 7 print('Bob:I will help you.') 8 9 def com(self): 10 print('Bob:I am here to accompany you.') 11 12 13 # Observer 14 class Eve_Observer(): 15 def save(self): 16 print('Eve:Go away. Let me save her.') 17 18 def com(self): 19 print('Eve:Go away and let me go with her.') 20 21 22 # Observable 23 class Alice_Observable(): 24 Bob = Bob_Observer 25 Eve = Eve_Observer 26 27 def __init__(self,Bobobj,Eveobj): 28 self.Bob = Bobobj 29 self.Eve = Eveobj 30 31 def call_help(self): 32 print('Alice:Help!') 33 self.Bob.save() 34 self.Eve.save() 35 36 def call_com(self): 37 print('Alice:Who will go shopping with me?') 38 self.Bob.com() 39 self.Eve.com() 40 41 42 # interface 43 class Run(): 44 Alice = Alice_Observable 45 def __init__(self,Aliceobj): 46 self.Alice = Aliceobj 47 def runhelp (self): 48 self.Alice.call_help() 49 def runcom (self): 50 self.Alice.call_com() 51 52 53 if __name__== '__main__': 54 m = Bob_Observer() 55 g = Eve_Observer() 56 h = Alice_Observable(m, g) 57 run = Run(h) 58 run.runhelp() 59 print('--- *_* ---') 60 run.runcom()
其中,Alice_Observable为目标对象,Bob_Observer为、Eve为观察者对象。
输出如下:
三、Django中观察者模式应用
GitHub链接:
https://github.com/django/django/blob/master/django/dispatch/dispatcher.py#L19
目标对象方法:
https://github.com/django/django/blob/master/django/dispatch/dispatcher.py#L152
1 def send(self, sender, **named): 2 """ 3 Send signal from sender to all connected receivers. 4 If any receiver raises an error, the error propagates back through send, 5 terminating the dispatch loop. So it's possible that all receivers 6 won't be called if an error is raised. 7 Arguments: 8 sender 9 The sender of the signal. Either a specific object or None. 10 named 11 Named arguments which will be passed to receivers. 12 Return a list of tuple pairs [(receiver, response), ... ]. 13 """ 14 if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS: 15 return [] 16 17 return [ 18 (receiver, receiver(signal=self, sender=sender, **named)) 19 for receiver in self._live_receivers(sender) 20 ]
观察者方法:
https://github.com/django/django/blob/master/django/dispatch/dispatcher.py#L272
1 def receiver(signal, **kwargs): 2 """ 3 A decorator for connecting receivers to signals. Used by passing in the 4 signal (or list of signals) and keyword arguments to connect:: 5 @receiver(post_save, sender=MyModel) 6 def signal_receiver(sender, **kwargs): 7 ... 8 @receiver([post_save, post_delete], sender=MyModel) 9 def signals_receiver(sender, **kwargs): 10 ... 11 """ 12 def _decorator(func): 13 if isinstance(signal, (list, tuple)): 14 for s in signal: 15 s.connect(func, **kwargs) 16 else: 17 signal.connect(func, **kwargs) 18 return func 19 return _decorator
将目标对象与观察者对象连接,以获取信号:
connect(self, receiver, sender=None, weak=True, dispatch_uid=None)
将目标对象与观察者对象之间的连接断开:
disconnect(self, receiver=None, sender=None, dispatch_uid=None)
使用观察者模式给项目带来的好处:
1.可以尽量多的使用继承,从而项目扩展性更强;
2.将所有的观察者抽象为观察者类,更加容易控制;
3.目标对象和观察者对象抽象耦合,符合低耦合的设计原则。
4.表示层和数据数据层分离,层间抽象接口,定义了稳定的连接、断开连接、消息更新机制,不同的表示层可以定义不同的具体观察者对象。
5.灵活实现了广播机制。