设计模式——观察者模式
设计模式——观察者模式
在上一篇文章中已经介绍了设计模式的一些基本原则,现在通过提出一个新问题引入我们即将介绍的观察者模式。还是以Car类作为我们介绍的例子,我们现在希望让Car拥有DashBoard(仪表盘),并且让仪表盘显示的数据随着Car的数据改变实时变化。在没学习Swift之前,如果让我用Java实现,我会在Car类中对Car的属性添加get方法,并在DashBoard类中添加更新仪表盘显示数据的方法,每次调用方法时动态的get需要的Car类的数据。
这么做犯下了一个原则性的错误,在设计模式入门中提到,不要针对具体实现编程,如果我们使用这个方法对仪表盘数据进行更新,我们必须在Car类中针对特定的仪表盘进行更新。但其实这么做距离我们实现观察者模式,只有一步之遥了,我们需要把指定的仪表盘,替换成多个观察者对象,而数据本身不用关心观察者对象的数量和具体实现,只需要在变化时调用观察者对象的方法即可,而这么做还有一个好处,我们可以动态的添加或者删除观察者,而不会影响数据运行的结果。像我们之前那样实现,DashBoard与Car的关联就被从代码层面写死了,我们如果想添加新的DashBoard必须修改代码,这就是两个对象之间耦合过深,所以引入下一条设计原则:
为了交互对象之间的松耦合设计而努力。
松耦合,又叫抽象耦合,的意思是两个对象可以进行交互,但不清楚彼此的细节,在我看来这就像一个沙漏结构,沙漏的两侧只通过很小的一个孔与另一侧交互,两侧彼此不知道对方还剩多少沙、容器的形状等等具体的细节,它们关心的仅仅是当前通过沙漏的数据。观察者模式的本质就是让观察者与被观察者松耦合。
被观察者不需要知道观察者将要执行的操作,观察者也不需要知道被观察者数据改变的原因,它只关心被观察者的数据是否发生变化,如果要变化观察者的话,只需要动态的注册与删除观察者就能实现。
最后使用观察者模式改造我们的Car类后Car类的代码如下:
1 |
|
Observable为接口,供可观察者实现,用于对观察者进行操作,包括通知观察者,注册新观察者,删除某特定观察者。改造后我们在Car类中就不会再看见具体实现的某个DashBoard类了。其实在Java中已经有自带的Observable和Observer,但是Java自带的实现与上文所说的略有区别,在Java中Observable是一个父类而非接口,我们通过继承这个父类实现可被观察的类,但我个人认为,这么做并不方便,在Java中只能继承一个类,但是可以实现多个接口,使用接口实现这个目的会更灵活。
Swift中的 didSet
和 willSet
与Observer Pattern
didSet和willSet在Swift是一个很实用的语法,提供了当变量被改变时进行操作的机会,但是这只是观察者模式的一部分,我们在上文提到,观察者模式的本质是实现观察者与被观察者的松耦合,观察者模式不是一种特定的语法,而是一种程序设计的思想。didSet仅仅只是为我们观察属性的变化提供了便利,并没有主动实现松耦合,如果我们依然将观察者写死在被观察者类中,就算使用了didSet,也不叫观察者模式。
我们思考一个问题,当两个对象互相为彼此的观察者,会发生什么事情?这样的两个对象之间的关系叫做循环依赖,当它们的值发生改变时会导致循环调用,进而引起程序崩溃,这是观察者模式的小小漏洞,我们需要在编程开发中格外注意。
参考: