观察者模式又名发布-订阅模式,定义了对象之间的一对多依赖,多个对象同时监听一个对象,当被监听对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新,被监听对象称为主题suject,监听对象称为观察者observer。
观察者模式结构如下(网上找的图):
简单来说,observer必须实现update方法,来接收suject状态变化时的通知及更新。suject维护一个observer列表,在状态变化时会逐个的调用observer的update方法来通知、更新observer,为此,suject须提供注册(添加observer到列表)、删除、通知更新三个方法。
观察者模式又分为两种模式:push和pull。push是指suject在状态变化时将所有的状态信息都发给observer,pull则是suject通知observer更新时,observer获取自己感兴趣的状态。
两种模式在实现上的区别:push模式下,observer的update方法接收的是状态信息,而pull模式下,update方法接收的是suject对象,这种情况下,suject须提供状态信息的get方法,让observer可以获取自己感兴趣的信息。
两种模式的优劣:push模式要求suject必须了解observer需要的状态,pull则是observer按需获取;push模式下observer的update方法的参数是具体的状态信息,发生变化时必须要重写update方法,pull模式则是将suject对象本身传给update,是最大的参数集合。
push模式具体实现:
- suject超类
package observer.push; import java.util.LinkedList; import java.util.List; /** * 推模式主题超类,能够注册、删除、数据变动时通知关注者 * @author sky * */ public abstract class Subject { /** * 观察者名单 */ private List<Observer> list = new LinkedList<>(); /** * 注册观察者 * @param o 观察者 */ public void addObserver(Observer o){ list.add(o); } /** * 删除观察者 * @param o 观察者 */ public void deleteObserver(Observer o){ int i = list.indexOf(o); if (i>-1) { list.remove(i); } } /** * 通知观察者 */ public void notifyObservers(String state){ for (Observer o:list) { o.update(state); } } }
- observer接口
package observer.push; /** * 推模式观察者接口 * @author sky * */ public interface Observer { public void update(String state); }
- suject具体实现类
package observer.push; public class ConcreteSubject extends Subject { /** * 状态 */ public String state; /** * 状态是否改变的标志 */ public boolean isChanged = false; /** * 状态改变后,通知观察者 */ public void change(){ if (isChanged) { this.notifyObservers(state); } } public String getState() { return state; } public void setState(String state) { this.state = state; isChanged = true; } public boolean isChanged() { return isChanged; } public void setChanged(boolean isChanged) { this.isChanged = isChanged; } }
- observ具体实现类
package observer.push; /** * 推模式观察者实现类 * @author sky * */ public class ConcreteObserver implements Observer { public String name; public ConcreteObserver(String n){ name=n; } @Override public void update(String state) { System.out.println(name+" update new state:"+state); } }
- 测试类:
package observer.push; public class Test { /** * @param args */ public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); Observer o1 = new ConcreteObserver("张山"); Observer o2 = new ConcreteObserver("李四"); subject.addObserver(o1); subject.addObserver(o2); System.out.println("准备:"); subject.setState("上班了"); subject.change(); subject.setState("下班了"); subject.change(); } }
- 输出:
准备: 张山 update new state:上班了 李四 update new state:上班了 张山 update new state:下班了 李四 update new state:下班了
pull模式实现:
- suject超类
package observer.pull; import java.util.LinkedList; import java.util.List; /** * 拉模式主题超类,能够注册、删除、数据变动时通知关注者 * @author sky * */ public abstract class Subject { /** * 观察者名单 */ private List<Observer> list = new LinkedList<>(); /** * 注册观察者 * @param o 观察者 */ public void addObserver(Observer o){ list.add(o); } /** * 删除观察者 * @param o 观察者 */ public void deleteObserver(Observer o){ int i = list.indexOf(o); if (i>-1) { list.remove(i); } } /** * 通知观察者 */ public void notifyObservers(){ for (Observer o:list) { o.update(this); } } }
- observer接口
package observer.pull; /** * 拉模式观察者接口 * @author sky * */ public interface Observer { public void update(Subject s); }
- suject具体实现类
package observer.pull; public class ConcreteSubject extends Subject { /** * 状态 */ public String state; /** * 状态是否改变的标志 */ public boolean isChanged = false; /** * 状态改变后,通知观察者 */ public void change(){ if (isChanged) { this.notifyObservers(); } } public String getState() { return state; } public void setState(String state) { this.state = state; isChanged = true; } public boolean isChanged() { return isChanged; } public void setChanged(boolean isChanged) { this.isChanged = isChanged; } }
- observer具体实现类
package observer.pull; /** * 拉模式观察者实现类 * @author sky * */ public class ConcreteObserver implements Observer { public String name; public ConcreteObserver(String n){ name=n; } @Override public void update(Subject s) { String state = ((ConcreteSubject)s).getState(); System.out.println(name+" update new state:"+state); } }
- 测试类
package observer.pull; public class Test { /** * @param args */ public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); Observer o1 = new ConcreteObserver("张山"); Observer o2 = new ConcreteObserver("李四"); subject.addObserver(o1); subject.addObserver(o2); System.out.println("pull模式准备:"); subject.setState("上班了"); subject.change(); subject.setState("下班了"); subject.change(); } }
- 输出
pull模式准备: 张山 update new state:上班了 李四 update new state:上班了 张山 update new state:下班了 李四 update new state:下班了