观察者设计模式
是对象的行为模式,又称发布/订阅模式(publish/subscribe)模式,模/视图模式(model/view),源-监听模式(source/listener)
观察者模式定义一种一对多的依赖关系。让多个观察者同时监听一个主体对象,当主题对象的状态发生改变时,会通知所有的观察者,使其自动的更新自己。(相对
registerListener是一种一对一的关系,称为回调)。
观察者模式的结构
由上图我们可以知道观察者模式的组成:
抽象主题对象(Subject):抽象主题对象会把所有的观察者对象的引用保存在一个集合当中(通畅是ArrayList),抽象主题对象可以保存任意个观察者对象。提供两个
接口用于添加观察者对象,和删除观察者对象。定义一个Notify**方法,会逐个调用 观察者自身方法更新自己。抽象主体对象也叫作被观察者
对象(Observable);
具体主体对象(ConcreteSubject):将相关的状态存入具体观察者对象中,当具体观察者对象的状态发生改变时,会逐个通知被注册的观察者对象。
抽象观察者对象(Observer):为具体观察者定义一个统一的接口,在主体对象通知更新自身时调用此方法。
具体观察这对象(ConcreteObserver):存储一个与主题对象状态相协调的状态。实现抽象观察者对象的更新自身的方法。
源码:
抽象主题:
public class Subject {
ArrayList<Observer> observers;
public Subject() {
observers=new ArrayList<Observer>();
}
/**
* 注册
* @param obs
*/
public void attach(Observer obs){
if(obs == null){
throw new NullPointerException();
}
observers.add(obs);
}
/**
* 注销
* @param obs
*/
public void detach(Observer obs){
observers.remove(obs);
}
protected void notifyObservers(String newState) {
for(Observer obs:observers){
obs.update(newState);
}
}
}
具体主题对象:
public class ConcreteSubject extends Subject{
private String state;
public String getState(){
return state;
}
public void change(String newState){
state=newState;
System.out.println("主题状态:"+state);
notifyObservers(state);
}
}
抽象观察者对象:
public interface Observer {
public void update(String newState);
}
具体观察者对象:
public class ConcreteObserver implements Observer{
private String observerState;
@Override
public void update(String newState) {
observerState = newState;
System.out.println("观察者转态:"+newState);
}
}
客户端对象:
public class Client {
public static void main(String[] args) {
ConcreteSubject subject =new ConcreteSubject();
Observer obs=new ConcreteObserver();
subject.attach(obs);
subject.change("newstate");
}
}
运行结果:
主题状态:newstate
观察者转态:newstate
推模式和拉模式
观察者模式根据update的传参不同分为推模式和拉模式。
推模式:主体对象向观察者对象推送主体对象的详细信息,不过观察者对象是否需要。(上面就是推模式)
拉模式:主题对象把自身的引用传递给观察者对象。观察者对象想用什么信息,直接通过主题对象的引用自己获取。
拉模式源码(在上面的基础做局部修改):
抽象主题:
public class Subject {
ArrayList<Observer> observers;
public Subject() {
observers=new ArrayList<Observer>();
}
/**
* 注册
* @param obs
*/
public void attach(Observer obs){
if(obs == null){
throw new NullPointerException();
}
observers.add(obs);
}
/**
* 注销
* @param obs
*/
public void detach(Observer obs){
observers.remove(obs);
}
protected void notifyObservers() {
for(Observer obs:observers){
obs.update(this);
}
}
}
具体主题对象:
public class ConcreteSubject extends Subject{
private String state;
public String getState(){
return state;
}
public void change(String newState){
state=newState;
System.out.println("主题状态:"+state);
notifyObservers();
}
}
抽象观察者:
public interface Observer {
public void update(Subject sub);
}
具体观察者:
public class ConcreteObserver implements Observer{
private String observerState;
@Override
public void update(Subject sub) {
observerState = ((ConcreteSubject)sub).getState();
System.out.println("观察者转态:"+observerState);
}
}
客户端:
public class Client {
public static void main(String[] args) {
ConcreteSubject subject =new ConcreteSubject();
Observer obs=new ConcreteObserver();
subject.attach(obs);
subject.change("newstate");
}
}
推模式是假定主体对象知道观察者需要的数据类型,拉模式则是主体对象不知道观察者需要的数据类型,所以干脆将自身引用传递过去,观察者对象需要什么对象自己去取。
推模式的update方法是按需要定义参数,很难被复用。拉模式则只需在接口处多定义一个取参数的接口,就可以实现复用。