参考书籍:
在商业项目中第一次读到观察者模式的代码是一个异步服务器消息分发的实现部分。由此开始学习了一下 。
- 设计模式中一句出现频率非常高的话是,“ 在不改动。。。。的情况下, 实现。。。。的扩展“ 。
- 对于设计模式的学习者来说,充分思考这句话其实非常重要, 因为这句往往只对框架/ 工具包的设计才有真正的意义。因为框架和工具包存在的意义,就是为了让其他的程序员予以利用, 进行功能的扩展,而这种功能的扩展必须以不需要改动框架和工具包中代码为前提
- 对于应用程序的编写者, 从理论上来说, 所有的应用层级代码至少都是处于可编辑范围内的, 如果不细加考量, 就盲目使用较为复杂的设计模式, 反而会得不偿失, 毕竟灵活性的获得, 也是有代价的。
如果说单例模式和工厂方法模式是入门级程序员都必须掌握的方法, 那么观察者模式则是所有实际项目开发者都会直接或者间接用到的模式, 原因是:
观察者模式是MVC模式的一种更为泛化的描述(引自参考书籍1)
观察者模式顾名思义, 主要有两种角色:
这种关系在 java 语言中, 可以按照如下形式实现(不止这一种实现形式)
abstract class A {
private B b;
}
这种关系在 java 语言中, 可以按照如下形式实现(不止这一种实现形式)
abstract class A {
private List<B> b;
}
注意: A, B 的类型比较灵活, 可以是 class, abstract class , interface 的任意一种类型, 使用哪种完全看需求
class A extends B{
}
或
class A implements B{
}
上面的结构图省略了一个对初学者而言很重要的信息,观察者与观察对象的关联是何时建立的。
那么紧接着的第二个问题是图例中Observer 并没有 Subject 的引用, 如何调用其Attach/Detach 方法
观察者模式在下列情形时应当被使用:
观察者模式在实现时,需要考虑的一些问题
问题1: 被观察者与观察者对应关系的维护方式
问题2: 当一个观察者需要观察不止一个被观察者时,当收到一个通知时, 如何知道是哪一个被观察者发来了通知。
问题3: 何时调用Notify方法()
问题4: 当一个被观察者被删除时, 应该对相应的观察者作何处理。
问题5: 如何保证观察者对象在调用Notify方法之前,自身的状态处于一个正常的状态,而不是修改到一半的状态。
// 被观察者基类
public class BaseSubject {
private int value = 0;
public void operation(int newValue)
{
value = 1;
notifyObservers()
}
public void notify()
{
...
}
}
//被观察者子类
public class MySubject extends BaseSubject {
private int myValue = 2;
public void myOperation( int newValue)
{
super.operation(newValue); // 这个操作已经触发了notify 方法
this.myValue += newValue;
.... // 后续的对被观察者子对象的状态修改尚未被通知给观察者,除非最后显示调用了notifyObservers() 方法
}
}
这个问题可以通过设计模式之模板方法(Template Method) 模式避免。 具体方案是定义一个元操作供子类重写, 然后在模板方法中将 notify () 操作放在模板方法中最后进行的操作,以此来保证当观察者子类重写观察者基类时, 不会遗漏Notify 操作。
void attach(Observer o, Aspect interest);
使得观察者在注册时,同时告诉被观察者他关心的事件类别。 而被观察者在特定的事件发生,可以仅仅通知那些注册了该类别事件的观察者。