说明:本文参照《大话设计模式》中的案例做简要解析
观察者模式:
又叫发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在发生变化时,会通知所有观察者对象,使他们能够更新自己。
我自己的理解,可以拿咱们都比较熟悉的上课来做比喻,在一个教室里,老师就是通知者,所有正在上课的学生就是观察者,老师说下课,所有的学生下课回家。老师说的“下课”,就是这里的“主题”,也可以叫话题(Topic),学生接受到这个“主题”,采取相应的动作-(收拾东西回家)。
类图及简要说明:
Subject类,可理解为主题或者抽象通知者,一般用抽象类或接口实现。它把所有的观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者。
package com.uu.designPattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
***********************************************
* 主题或抽象通知者
* 一般用一个抽象类或一个接口实现,把所有对观察者的引用保存在一个集合里,每一个主题都可以有任何数量的观察者。
* 抽象主题提供一个接口,可以增加和删除观察者。
* @author UU
* @date 2018年7月5日 下午3:00:23
* @version 1.0
***********************************************
*/
public abstract class Subject {
List<Observer> observers = new ArrayList<>();
/**添加观察者*/
public abstract void attach(Observer observer);
/**移除观察者*/
public abstract void detach(Observer observer);
/**
* 通知观察者
*/
public void notifyAllObserver() {
observers.forEach(Observer::update);
}
}
Observer,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时,更新自己。这个接口称为更新接口,更新接口一般都有一个update方法。
package com.uu.designPattern.observer;
/**
***********************************************
* 观察者
* @author UU
* @date 2018年7月5日 下午3:02:34
* @version 1.0
***********************************************
*/
public abstract class Observer {
public abstract void update();
}
ConcreteSubject,具体的主题或具体的通知者,将有关状态存入具体观察者对象;在具体主题的内部状态发生改变时,给所有已经注册的观察者发出通知。其实这里的意思主要是触发通知者发出通知,然后观察者根据通知信息作出相应的动作。
package com.uu.designPattern.observer;
/**
***********************************************
* 具体的主题或通知者,将有关状态存入具体主题对象,在具体的主题对象的内部状态发生改变时,通知所有已经注册的观察者
* @author UU
* @date 2018年7月5日 下午3:42:40
* @version 1.0
***********************************************
*/
public class ConcreteSubject extends Subject{
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public void attach(Observer observer) {
this.observers.add(observer);
}
@Override
public void detach(Observer observer) {
this.observers.remove(observer);
}
}
ConcreteObserver,具体的观察者,实现抽象观察者所要实现的更新方法,以便使自身的状态与主题的状态保持一致。具体观察者包含一个具体主题对象的引用。
package com.uu.designPattern.observer;
/**
***********************************************
* 具体的观察者
*
* @author UU
* @date 2018年7月5日 下午3:46:47
* @version 1.0
***********************************************
*/
public class ConcreteObserver extends Observer {
private String name;
private String state;
private ConcreteSubject subject;
public ConcreteObserver(String name, ConcreteSubject subject) {
super();
this.name = name;
this.subject = subject;
}
@Override
public void update() {
state = subject.getState();
System.out.println("观察者" + this.name + "的新状态是:" + state);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public ConcreteSubject getSubject() {
return subject;
}
public void setSubject(ConcreteSubject subject) {
this.subject = subject;
}
}
测试类:
package com.uu.designPattern.observer;
public class ObserverTest {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
subject.attach(new ConcreteObserver("AA", subject));
subject.attach(new ConcreteObserver("BB", subject));
subject.setState("ABC");
subject.notifyAllObserver();
subject.setState("CCC");
subject.notifyAllObserver();
}
}
运行结果:
观察者AA的新状态是:ABC
观察者BB的新状态是:ABC
观察者AA的新状态是:CCC
观察者BB的新状态是:CCC
观察者模式的特点:
主要是为了解决各类直接的耦合度,一个出题可以有任意数量的观察者,一旦主题发生改变,所有注册的观察者都可以得到通知。主题发出通知时,并不需要知道他的观察者都是哪些,也就是说,具体的观察者是谁,他根本不需要知道,而任何一个观察者不知道也不需要知道其他观察者的存在。
再拿老师和学生来讲,老师不需要知道每个学生都是谁(也许是刚来的新老师),老师只需要发出下课的指令就可以了,然后这个指令会被所有正在上课的学生接受到。对于每个学生个体而言,也不需要知道是否有其他学生是否存在,只要接受到老师的指令,照做就OK了。
观察者模式的应用场景:
当一个对象的改变需要同时改变其他对象时,并且它不知道具体有多少对象需要改变。
总的来讲,观察者模式所做的工作就是解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化。
在Dubbo的注册中心Zookeeper中的服务注册和订阅应用的就是这种模式。
以上全是个人见解,若有错误,还望指正。