什么是观察者模式
观察者模式应该是我们日常中听说的最多,同时也是经常使用的设计模式。那么什么是观察者模式?
举一个校园生活中的例子吧:
大家上学时分辨上课和下课都是靠铃声的吧。打上课铃的时候学生A回到教室上课,打下课铃的时候学生A走出教室下课
那么我们可能这样来设计:
@interface Student : NSObject
- (void)goInClassroom;
- (void)goOutClassroom;
@end
@interface Bell : NSObject
@property (nonatomic, strong) Student *studentA;
- (void)classBegin;
- (void)classEnd;
@end
是不是看起来很简单?当Bell响起classBegin声时,学生goInClassroom,反之goOutClassroom。日常中编码过程中我们也很可能是这样来设计的。当结构简单的时候这样做当然没有问题。然而学校不可能只有一个学生,在学生日渐多起来的时候,我们可能用一个数组来管理:
@property (nonatomic, copy) NSArray *studentArray;
然而,不仅仅有学生去遵守铃声来分辨上下课,还有老师、辅导员、还有一些比如负责设备的后勤人员,打扫卫生的阿姨都需要对铃声做出响应的反应,那么铃声需要维护这么多的角色的数组和他们对不同的铃声状态的操作,耦合性太高,非常不容易管理。这个时候,就需要用到观察者模式。
观察者(Observer)模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。同时减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作(Collaboration)。观察者模式是满足这一要求的各种设计方案中最重要的一种。
观察者模式的类图与结构
可以上图看出,观察者模式的实现里有下面这些角色:
抽象主题(Subject)角色:上面例子中响铃的抽象(想象下如果停电了,是不是还有手摇铃,或者教导主任的喊话等等都可以担任和响铃一样的作用)即为抽象主题角色。主题角色持有观察者的对象的聚集。抽象主题提供接口可以增加和删除观察者对象。
抽象观察者(Observer)角色:上面例子中所有需要为铃声响应的人的抽象即为抽象观察者角色。为所有的具体观察者定义一个更新接口。在上图的实现中,更新接口只包含一个方法(Update())方法,这个方法叫更新方法。
具体主题(ConcreteSubject)角色:上面例子中的响铃就是一个具体主题角色。将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。
具体观察者(ConcreteObserver)角色:上面例子中每个学生、老师、后勤人员都是一个个具体观察者角色。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题对象的引用。
需要注意的是具体主题角色和抽象观察者角色是聚合关系,代表具体主题对象可以持有任意个抽象观察者对象,而不是具体观察者,意味着主题对象不需要知道持有了哪些ConcreteObserver类型,而只知道抽象Observer类型。就像我们上面的例子中,铃声并不需要知道它通知到的是老师还是学生一样。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要的时候调用每一个观察者共有的Update()方法。这种做法叫做"针对抽象编程"。
以上不对之处敬请批评指正,下一节利用通知来实现观察者模式
本文系作者原创,转载请注明出处