当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。主要解决一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
大话设计模式中程杰老师对观察者模式的定义是,观察者模式:定义对象间的一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式结构图如下:
示例代码:
package com.dfcDemo.observer;
import java.util.ArrayList;
import java.util.List;
/** * 抽象主题类或者抽象观察者类,一般用一个抽象类或者一个接口实现, * 它把所有对对象的引用保存在一个集合中,每个主题都可以有任意数 * 量的观察者 * @author lmb * */
public abstract class Subject {
private List<Observer> observers = new ArrayList<Observer>();
//add observer
public void attach(Observer observer){
observers.add(observer);
}
//remove observer
public void detach(Observer observer){
observers.remove(observer);
}
//send notify to observers
public void sendNotify(){
for(Observer o : observers){
o.update();
}
}
}
package com.dfcDemo.observer;
/** * 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己 * @author lmb * */
public abstract class Observer {
public abstract void update();
}
package com.dfcDemo.observer;
/** * 具体通知者,将有关状态存入具体观察者对象; * 在具体主题的内部状态改变时,给所有登记过的观察者发出通知。 * 具体主题角色通常用一个具体子类实现 * @author lmb * */
public class ConcreteSubject extends Subject{
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
package com.dfcDemo.observer;
/** * 具体观察者:实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调 * @author lmb * */
public class ConcreteObserver extends Observer{
private String observerState;
private ConcreteSubject subject;
public String name;
//constructor
public ConcreteObserver(ConcreteSubject subject, String name){
this.subject = subject;
this.name = name;
}
public ConcreteSubject subject(){
return subject;
}
@Override
public void update() {
observerState = subject.getSubjectState();
System.out.println("The observer's state of " + name + " is " + observerState);
}
}
package com.dfcDemo.observer;
public class TestObserver {
public static void main(String[] args) {
//build the object of subject
ConcreteSubject subject = new ConcreteSubject();
//add observer for the object of subject
subject.attach(new ConcreteObserver(subject,"observer Tom"));
subject.attach(new ConcreteObserver(subject,"observer Jerry"));
subject.attach(new ConcreteObserver(subject,"observer Jack"));
//set the state of subject
subject.setSubjectState("ready");
subject.sendNotify();
}
}
运行结果:
The observer's state of observer Tom is ready The observer's state of observer Jerry is ready
The observer's state of observer Jack is ready
观察者模式的特点:
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生改变,所有的Observer都可以得到通知。Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁它根本不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
使用场景:
1、当一个对象的改变需要同时改变其他对象,并且它不知道具体有多少对象有待改变时,应考虑使用观察者模式;
2、一个抽象模型有两个方面,其中一方面依赖与另一方面,这是观察者模式可以将这两者封装在独立的对象中是它们各自独立地改变和复用。
总的来讲,观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。
优点
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
缺点
依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
改进
使用事件和委托来改进