一、什么是观察者模式?
又叫做发布-订阅模式,定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:
其中涉及到四种角色:
1.抽象目标(或抽象主题,抽象被观察者):提供了用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
2.具体目标(或具体主题,具体被观察者):继承Subject类,在这里实现具体业务。
3.抽象观察者:一般是一个抽象类或接口,它包含了一个更新的方法,当接到具体主题的更改通知时被调用。
4.具体观察者:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
二、使用观察者模式的场景和优缺点
1.场景
- 关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
2.优点
解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。
3.缺点
(1)在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
三、观察者模式的代码样例
1.抽象目标:Subject
abstract class Subject {
//容器
protected List<Observer> observers = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
//通知观察者方法
public abstract void notifyObserver();
}
2、具体目标:ConcreteSubject
public class ConcreteSubject extends Subject {
@Override
public void notifyObserver() {
System.out.println("具体目标发生改变...");
for (Object obs : observers) {
((Observer) obs).response();
}
}
}
3、抽象观察者:Observer
public interface Observer {
void response(); //反应
}
4.具体观察者1:ConcreteObserver1
public class ConcreteObserver1 implements Observer {
@Override
public void response() {
System.out.println("具体观察者1做出反应");
}
}
5.具体观察者2:ConcreteObserver2
public class ConcreteObserver2 implements Observer{
@Override
public void response() {
System.out.println("具体观察者2做出反应");
}
}
6、主方法测试
public class TestMain {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer obs1 = new ConcreteObserver1();
Observer obs2 = new ConcreteObserver2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
控制台打印
具体目标发生改变...
具体观察者1做出反应
具体观察者2做出反应