1.什么是观察者模式?
定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时其相关依赖对象皆得到通知并自动更新。
举个例子:红绿灯是一个,车是多个。红绿灯变了,车会有对应的行为。
观察者模式的别是有发布-订阅模式、模型-视图模式、源-监听器模式、从属者模式。
2.观察者模式结构
(1)Subject(目标):是被观察者对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。
(2)ConcreteSubject(具体目标):具体目标是目标类的子类,它通常包含有经常发生改变的数据,当它的状态发生改变时将向它的各个观察者发出通知。同时它还实现了在目标类中定义的抽象业务逻辑方法。如果无需扩展目标类,则具体目标类可以省略。
(3)Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者
(4)ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致。它实现了在抽象观察者中定义的update()方法。通常在实现时可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
3.观察者模式的实现
(1)目标类
/**
* 目标
*/
public abstract class Subject {
//定义一个观察者集合用于存储所有观察者对象
protected ArrayList<Observer> observers = new ArrayList();
//注册方法,用于向观察者集合中增加一个观察者
public void attach(Observer observer){
observers.add(observer);
}
//注销方法,用于从观察者集合中删除一个观察者
public void detach(Observer observer){
observers.remove(observer);
}
//声明抽象通知方法
public abstract void notify2();
}
(2)具体目标类
/**
* 具体目标类
*/
public class ConcreteSubject extends Subject {
//事先通知方法
@Override
public void notify2() {
//遍历观察者集合,调用每一个观察者的响应方法
for (Object obs : observers){
((Observer)obs).update();
}
}
}
(3)观察者
/**
* 观察者
*/
public interface Observer {
//声明响应方法
public void update();
}
(4)具体观察者
/**
* 具体观察者
*/
public class ConcreteObserver implements Observer {
@Override
public void update() {
}
}
4.观察者模式实例——战队一人受到攻击,其他成员可以受到这个人的求助
(1)指挥部类,充当抽象目标类
/**
* 指挥部类,充当抽象目标类
*/
public abstract class AllyControlCenter {
protected String allyName;//战队名称
protected ArrayList<Observer> players = new ArrayList<Observer>();//定义一个集合用于保存战队成员
//注册方法
public void join(Observer observer){
System.out.println(observer.getName()+"加入"+this.allyName+"战队!");
players.add(observer);
}
//注销方法
public void quit(Observer observer){
System.out.println(observer.getName()+"退出"+this.allyName+"战队!");
players.remove(observer);
}
//声明抽象通知方法
public abstract void notifyObserver(String name);
public String getAllyName() {
return allyName;
}
public void setAllyName(String allyName) {
this.allyName = allyName;
}
}
(2)具体指挥部类,充当具体目标类
/**
* 具体指挥部类,充当具体目标类
*/
public class ConcreteAllyControlCenter extends AllyControlCenter {
public ConcreteAllyControlCenter(String allyName){
System.out.println(allyName+"战队组建成功!");
System.out.println("---------------");
this.allyName = allyName;
}
@Override
public void notifyObserver(String name) {
System.out.println(this.allyName+"战队紧急通知,盟友"+name+"遭受敌人攻击!");
//遍历观察者集合,调用每一个盟友(除自己)的支援方法
for (Object obs:players){
if(!((Observer)obs).getName().equalsIgnoreCase(name)){
((Observer)obs).help();
}
}
}
}
(3)抽象观察者类
/**
* 抽象观察者类
*/
public interface Observer {
public String getName();
public void setName(String name);
public void help();//声明支援盟友方法
public void beAttacker(AllyControlCenter acc);//声明遭受攻击方法
}
(4)战队成员类,充当具体观察者类
/**
* 战队成员类,充当具体观察者类
*/
public class Player implements Observer {
private String name;
public Player(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void help() {
System.out.println("坚持住,"+this.name+"来救你了!");
}
@Override
public void beAttacker(AllyControlCenter acc) {
System.out.println(this.name+"被攻击!");
acc.notifyObserver(name);
}
}
(5)客户端
public class Client {
public static void main(String[] args) {
//定义观察目标对象
AllyControlCenter acc;
acc = new ConcreteAllyControlCenter("金庸群侠");
//定义4个观察者对象
Observer player1,player2,player3,player4;
player1 = new Player("杨过");
acc.join(player1);
player2 = new Player("令狐冲");
acc.join(player2);
player3 = new Player("张无忌");
acc.join(player3);
player4 = new Player("段誉");
acc.join(player4);
//某成员遭受攻击
player1.beAttacker(acc);
}
}
(6)结果及路径
5.JDK对观察者模式的支持
Observable类以及Observer接口,构成了JDK对观察者模式的支持。
(1)Observer接口
void update(Observable o,Object arg);
当观察目标的状态发生变化时该方法将会调用,在Observer的子类中将实现update()方法,即具体观察者可以根据需求具有不同的更新行为。
当调用观察目标类Observable的notifyObservers()方法时将执行观察者类中的update()方法。
(2)Observable类
充当观察目标类,其中定义了一个向量Vector来存储观察者对象。
用户可以直接用Observer接口和Observable类作为观察者模式的抽象层,再自定义具体观察者类和具体观察目标类。通过JDK中的Observer接口和Observable类可以更加方便的在java语言中使用观察者模式。
6.观察者模式与Java事件处理
Java1.1以后,事件处理模式采用基于观察者模式的委派事件模型,即一个java组件所引发的事件并不由引发事件的对象自己来负责处理,而是委派给独立的时间处理对象负责。
一般界面组件(目标角色)负责发布事件,事件处理者(观察者角色)可以向目标订阅它感兴趣的事件。当一个具体目标产生一个事件时,它将通知所有的订阅者。事件的发布者成为事件源,订阅者成为事件监听器,在这个过程中通过事件对象来传递与事件相关的信息。可以在事件监听器的实现类中实现事件处理,因此事件监听对象又可以称为事件处理对象。
事件源对象,事件监听对象(事件处理对象),事件对象构成了Java事件处理模型的三要素。事件源对象充当观察目标,事件监听对象充当观察者。
7.观察者模式与MVC
MVC = 模型 + 视图 + 控制器
模型可对应于观察者模式中的观察目标,视图对应观察者,控制器充当两者的中介者。当模型层数据发生改变,视图层将自动改变其显示内容。
8.观察者模式的优缺点
优:
(1)实现表示层和数据逻辑层的分离
(2)观察目标和观察者建立一个抽象的耦合
(3)支持广播
缺:
(1)一个观察目标有很多观察者,会花费很多时间
(2)如果存在循环依赖,会导致循环调用
(3)观察者模式没有对应机制让观察者知道目标对象是怎么发生变化的,只能知道它发生了变化
9.观察者模式适用环境
(1)一个抽象模型有两个方面,其中一方面依赖于另一方面,将这两方面封装在独立对象中使他们各自独立和可以复用
(2)一个对象的改变导致其他对象也跟着变化
(3)触发链,A影响B,B影响C。。。