设计模式之观察者模式
概述
观察者模式又叫做发布/订阅模型(Publish/Subscribe)。当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
设计模式思想
观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这一模式中的关键对象是观察目标和观察者,一个目标可以有任意数目的与之相依赖的观察者,一旦目标的状态发生改变,所有的观察者都将得到通知。
作为对这个通知的响应,每个观察者都将即时更新自己的状态,以与目标状态同步,这种交互也称为发布-订阅(publishsubscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。
设计模式的写法
观察者模式主要有四个角色:
抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
代码:
被观察者抽象接口Subject:
package com.designpattern.Observe;
/**
* 观察者模式-----Subject 被观察者,即观察者观察的对象
*
* @author Administrator
*
*/
public interface Subject {
/* 增加观察者 */
public void add(Observer observer);
/* 删除观察者 */
public void del(Observer observer);
/* 通知所有的观察者 */
public void notifyObservers();
/* 自身的操作 */
public void operation();
}
被观察者实体类:
package com.designpattern.Observe;
import java.util.Enumeration;
import java.util.Vector;
/**
* 被观察者实体类
* @author Administrator
*
*/
public abstract class AbstractSubject implements Subject {
private Vector<Observer> vector = new Vector<Observer>();
@Override
public void add(Observer observer) {
// TODO Auto-generated method stub
vector.add(observer);
System.out.println("发现1个警察");
}
@Override
public void del(Observer observer) {
// TODO Auto-generated method stub
vector.remove(observer);
System.out.println("甩掉1个警察");
}
@Override
public void notifyObservers() {
// TODO Auto-generated method stub
for (Observer observer : vector) {
observer.update();
}
}
}
package com.designpattern.Observe;
/**
* 被观察者实体操作类
* @author Administrator
*
*/
public class EntitySubject extends AbstractSubject{
@Override
public void operation() {
// TODO Auto-generated method stub
System.out.println("有人监视我,该跑路了!");
notifyObservers();
}
}
抽象观察者Observe:
package com.designpattern.Observe;
/**
* 观察者模式-----Observer观察者
* @author Administrator
*创建抽象观察者接口
*/
public interface Observer {
public void update();
}
具体观察者:
package com.designpattern.Observe;
/**
* 创建实体观察者1
* @author Administrator
*
*/
public class ObserverOne implements Observer{
@Override
public void update() {
// TODO Auto-generated method stub
System.out.println("我是警察A,我观察到目标要跑路了,准备抓捕!");
}
}
package com.designpattern.Observe;
/**
* 创建实体观察者2
* @author Administrator
*
*/
public class ObserverTwo implements Observer{
@Override
public void update() {
// TODO Auto-generated method stub
System.out.println("我是警察B,我观察到目标要跑路了,准备抓捕!");
}
}
package com.designpattern.Observe;
/**
* 创建实体观察者3
* @author Administrator
*
*/
public class ObserverThree implements Observer{
@Override
public void update() {
// TODO Auto-generated method stub
System.out.println("我是警察C,我观察到目标要跑路了,准备抓捕!");
}
}
测试类:
package com.designpattern.Observe.test;
import com.designpattern.Observe.EntitySubject;
import com.designpattern.Observe.ObserverOne;
import com.designpattern.Observe.ObserverThree;
import com.designpattern.Observe.ObserverTwo;
import com.designpattern.Observe.Subject;
/**
* 客户端测试类
* @author Administrator
*
*/
public class TestObserve {
public static void main(String[] args) {
Subject subject = new EntitySubject();
subject.add(new ObserverOne());
subject.add(new ObserverTwo());
subject.add(new ObserverThree());
subject.operation();
}
}
测试效果:
发现1个警察
发现1个警察
发现1个警察
甩掉1个警察
有人监视我,该跑路了!
我是警察A,我观察到目标要跑路了,准备抓捕!
我是警察B,我观察到目标要跑路了,准备抓捕!
我是警察C,我观察到目标要跑路了,准备抓捕!
优缺点
优点:
1、观察者和被观察者是抽象耦合的。
2、建立一套触发机制。
缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法。
总结
观察者模式将观察者和主题(被观察者)彻底解耦。任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现了Observer接口的对象列表。主题只知道观察者实现了某一接口(也就是Observer接口)。并不需要观察者的具体类是谁、做了些什么或者其他任何细节,这也是观察者模式的局限所在。