观察者模式(也被称为发布/订阅模式)提供了避免组件之间紧密耦合的另一种方法,它将观察者(Observer)和被观察者(Observable)的对象分离开来。在该模式中,一个对象通过添加一个方法(该方法允许另一个对象,即观察者(Observer)注册自己)使本身变得可观察(Observable)。当可观察(Observable)的对象更改时,它会将消息发送到已注册的观察者(Observer)。这些观察者(Observer)使用该信息执行的操作与可观察者(Observable)的对象无关,结果是对象可以相互对话,而不必了解原因。
- Subject:抽象主题,也就是被观察者本身(Observable)的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者(Observer),抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体被观察者(ConcreteObservable)角色。
- Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得主题的更改通知时更新自己。
- ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便主题的状态发生变化时更新自身的状态。
例:
开发技术前线网站(www.devtf.cn)支持用户邮箱订阅,每周发布周报后会将优质的内容推送给订阅用户,这种模式叫做发布-订阅模式,即是观察者模式。
/*订阅的程序员是观察者*/
public class Coder implements Observer{
public String name;
public Coder(String aName){
this.name = aName;
}
@Override
public void update(Observable o, Object arg){
System.out.println("Hi," + name + ", 技术前线更新啦,内容:" + arg);
}
@Ovrride
public String toString(){
return "码农:"+ name;
}
}
/*网站是被观察者,当它更新时,所有的观察者都会接到相应的通知*/
public class DevTechFrontier extends Observable{
public void postNewPublication(String content){
setChange(); //标识状态或者内容发生改变
notifyObservers(content); //通知所有观察者
}
}
public class Test{
public static void main(String []args){
//被观察的角色
DevTechFrontier mDevTechFrontier = new DevTechFrontier();
//观察者
Coder coder1 = new Coder("coder1");
Coder coder2 = new Coder("coder2");
Coder coder3 = new Coder("coder3");
//将观察者注册到可观察对象的观察者列表中
mDevTechFrontier.addObserver(coder1);
mDevTechFrontier.addObserver(coder2);
mDevTechFrontier.addObserver(coder3);
mDevTechFrontier.postNewPublication("新的一期技术周报发布啦!");
}
}
Observer和Observable是JDK中的内置类型,可见观察者模式是非常重要的。这里Observer是抽象的观察者角色,Coder是具体观察者角色;Observable对应的是抽象主题角色,mDevTechFrontier是具体的主题角色。Coder订阅了mDevTechFrontier这个具体的可观察对象,当mDevTechFrontier更新时,会遍历所有观察者(Coder),然后给这些观察者发布一个更新的消息,即调用Coder的update方法,这样就达到了一对多的通知功能。在这个过程中,通知系统都是依赖Observer和Observable这些抽象类,因此,对于Coder和mDevTechFrontier完全没有耦合,保证了订阅系统的灵活性和扩展性。(摘自:Android源码设计模式解析与实战)