1.场景模式抽象
订阅报纸的过程,如果报纸来了的时间不确定,那么订报纸的人如何知道呢?可以抽象为:当一个对象的状态发生改变的时候,如何让依赖他的所有对象得到通知,并进行相应的处理呢?生活中最常见的例子就是:当你一上线,QQ后台就给你不上线的时候收到的所有的消息。
2.使用观察者模式来解决方案
2.1观察者模式定义
定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变的时候,所有依赖他的对象都得到通知并进行自动更新。
2.2观察者模式结构说明
2.3.观察者模式示例代码
package demo11.observer.example1; import java.util.*; /** * 目标对象,它知道观察它的观察者,并提供注册和删除观察者的接口 */ public class Subject { /** * 用来保存注册的观察者对象 */ private List<Observer> observers = new ArrayList<Observer>(); /** * 注册观察者对象 * @param observer 观察者对象 */ public void attach(Observer observer) { observers.add(observer); } /** * 删除观察者对象 * @param observer 观察者对象 */ public void detach(Observer observer) { observers.remove(observer); } /** * 通知所有注册的观察者对象 */ protected void notifyObservers() { for(Observer observer : observers){ observer.update(this); } } } *************************************************************************************************** package demo11.observer.example1; /** * 具体的目标对象,负责把有关状态存入到相应的观察者对象, * 并在自己状态发生改变时,通知各个观察者 */ public class ConcreteSubject extends Subject { /** * 示意,目标对象的状态 */ private String subjectState; public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; //状态发生了改变,通知各个观察者 this.notifyObservers(); } } *************************************************************************************************** package demo11.observer.example1; /** * 观察者接口,定义一个更新的接口给那些在目标发生改变的时候被通知的对象 */ public interface Observer { /** * 更新的接口 * @param subject 传入目标对象,好获取相应的目标对象的状态 */ public void update(Subject subject); } *************************************************************************************************** package demo11.observer.example1; /** * 具体观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致 */ public class ConcreteObserver implements Observer { /** * 示意,观者者的状态 */ private String observerState; public void update(Subject subject) { // 具体的更新实现 //这里可能需要更新观察者的状态,使其与目标的状态保持一致 observerState = ((ConcreteSubject)subject).getSubjectState(); } }
3.使用观察者模式来实现示例
3.1目标对象,作为被观察者
package demo11.observer.example2; import java.util.ArrayList; import java.util.List; /** * 目标对象,作为被观察者 */ public class Subject { /** * 用来保存注册的观察者对象,也就是报纸的订阅者 */ private List<Observer> readers = new ArrayList<Observer>(); /** * 报纸的读者需要先向报社订阅,先要注册 * @param reader 报纸的读者 * @return 是否注册成功 */ public void attach(Observer reader) { readers.add(reader); } /** * 报纸的读者可以取消订阅 * @param reader 报纸的读者 * @return 是否取消成功 */ public void detach(Observer reader) { readers.remove(reader); } /** * 当每期报纸印刷出来后,就要迅速的主动的被送到读者的手中, * 相当于通知读者,让他们知道 */ protected void notifyObservers() { for(Observer reader : readers){ reader.update(this); } } }
3.2报纸对象,具体的目标实现
package demo11.observer.example2; /** * 报纸对象,具体的目标实现 */ public class NewsPaper extends Subject { /** * 报纸的具体内容 */ private String content; /** * 获取报纸的具体内容 * * @return 报纸的具体内容 */ public String getContent() { return content; } /** * 示意,设置报纸的具体内容,相当于要出版报纸了 * * @param content * 报纸的具体内容 */ public void setContent(String content) { this.content = content; // 内容有了,说明又出报纸了,那就通知所有的读者 notifyObservers(); } }
3.3观察者,比如报纸的读者
package demo11.observer.example2; /** * 观察者,比如报纸的读者 */ public interface Observer { /** * 被通知的方法 * @param subject 具体的目标对象,可以获取报纸的内容 */ public void update(Subject subject); }
3.4真正的读者,为了简单就描述一下姓名
package demo11.observer.example2; /** * 真正的读者,为了简单就描述一下姓名 */ public class Reader implements Observer{ /** * 读者的姓名 */ private String name; public void update(Subject subject) { //这是采用拉的方式 System.out.println(name+"收到报纸了,阅读先。内容是==="+((NewsPaper)subject).getContent()); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3.5客户端使用
package demo11.observer.example2; public class Client { public static void main(String[] args) { //创建一个报纸,作为被观察者 NewsPaper subject = new NewsPaper(); //创建阅读者,也就是观察者 Reader reader1 = new Reader(); reader1.setName("张三"); Reader reader2 = new Reader(); reader2.setName("李四"); Reader reader3 = new Reader(); reader3.setName("王五"); //注册阅读者 subject.attach(reader1); subject.attach(reader2); subject.attach(reader3); //要出报纸啦 subject.setContent("本期内容是观察者模式"); } }
4.认识观察者模式
4.1目标和观察者之间的关系
典型的一对多的关系。
4.2单向依赖
观察者依赖目标,目标不依赖观察者。
4.3观察者模式的调用顺序图
4.4推模型
推模型:顾名思义,目标对象主动向观察者推送消息,不管观察者是否需要,相当于广播通信
与前面不同的地方在于
public void update(String content) { //这是采用推的方式 System.out.println(name+"收到报纸了,阅读先。内容是==="+content); } /** * 当每期报纸印刷出来后,就要迅速的主动的被送到读者的手中, * 相当于通知读者,让他们知道 * @param content 要主动推送的内容 */ protected void notifyObservers(String content) { for(Observer reader : readers){ reader.update(content); } } /** * 示意,设置报纸的具体内容,相当于要出版报纸了 * @param content 报纸的具体内容 */ public void setContent(String content) { this.content = content; //内容有了,说明又出报纸了,那就通知所有的读者 notifyObservers(content); }
4.5拉模型
拉模型:顾名思义,目标对象在通知观察者的时候,只传递少量信息,如果观察者需要更具体的信息,由观察者主动到目标对象去获取。
public void update(Subject subject) { // 这是采用拉的方式 System.out.println(name + "收到报纸了,阅读先。内容是===" + ((NewsPaper) subject).getContent()); }
4.6java中的观察者模式
java中已经定义了观察者模式,详细的可以查查。这里不再复述。基本上差不多。
5.观察者模式思考
5.1优缺点:
优点:实现了观察者和目标之间的抽象耦合,实现了动态联动,支持广播通信
缺点:可能会引起无谓的操作
5.2观察者模式的本质:
触发联动