1、观察者模式的简单介绍:
a、核心:
- 观察者模式主要用于 1 : N 的通知中。当一个对象(目标对象 Subject 或者 Objservable )的状态变化时,他需要及时告知一系列的对象(观察者对象,Observer),令他们做出响应。
b、通知观察者的方式:
- 推:每次都会把通知以广播的方式发送给所有的观察者,所有的观察者只能够被动接收。
- 拉:观察者只要知道有情况即可。至于什么时候获取内容,获取什么内容,都可以自主决定。
2、简单的代码演示:
a、Subject 类为目标对象类(相当于一个容器,里面存放了一些的观察者对象),提供了在主题对象中注册观察者对象的方法。ConcreteSubject 为具体的主题对象,里面提供了一个 stateCode 的成员变量,并且在 setStateCode() 方法中使用父类的 notifyAllObserver() 方法。
package com.geeklicreed.observer; import java.util.ArrayList; import java.util.List; public class Subject { protected List<Observer> list = new ArrayList<Observer>(); public void registerObserver(Observer observer){ list.add(observer); } public void removeObserver(Observer observer){ list.remove(observer); } public void notifyAllObservers(){ for(Observer observer: list){ observer.update(this); } } }
package com.geeklicreed.observer; public class ConcreteSubject extends Subject{ private int stateCode = 0; public int getStateCode(){ return stateCode; } public void setStateCode(int stateCode){ this.stateCode = stateCode; notifyAllObservers(); } }
b、创建 Observer 接口,即抽象的观察者类,并创建一个实现了该接口的 ConcreteObserver 类。(在该类中也有一个 stateCode 的成员变量)
package com.geeklicreed.observer; public interface Observer { void update(Subject subject); }
package com.geeklicreed.observer; public class ConcreteObserver implements Observer{ //状态码应该和主题对象保持一致 private int stateCode = 0; public void update(Subject subject){ stateCode = ((ConcreteSubject)subject).getStateCode(); } public int getStateCode(){ return stateCode; } public void setStateCode(int stateCode){ this.stateCode = stateCode; } }
c、看看 Client 测试类中的输出结果以及示例代码的类图关系。
package com.geeklicreed.observer; public class Client { public static void main(String[] args) { ConcreteSubject concreteSubject = new ConcreteSubject(); ConcreteObserver concreteObserver1 = new ConcreteObserver(); ConcreteObserver concreteObserver2 = new ConcreteObserver(); ConcreteObserver concreteObserver3 = new ConcreteObserver(); concreteSubject.registerObserver(concreteObserver1); concreteSubject.registerObserver(concreteObserver2); concreteSubject.registerObserver(concreteObserver3); concreteSubject.setStateCode(1000); System.out.println("======================================"); System.out.println(concreteObserver1.getStateCode()); System.out.println(concreteObserver2.getStateCode()); System.out.println(concreteObserver3.getStateCode()); /*输出结果为: ====================================== 1000 1000 1000*/ } }
3、使用 javase 提供的 java.util.Observable 和 java.util.Observer 来实现观察者模式:
- Observable 类是目标类,Observer 接口是观察者接口,ConcreteSubject 是具体目标类,ConcreteObserver 是具体观察者类,使用 已经封装好的方法来实现我们的观察者模式。
package com.geeklicreed.observer; import java.util.Observable; public class ConcreteSubject extends Observable { private int stateCode; public void set(int state) { this.stateCode = state; setChanged(); notifyObservers(state); } public int getStateCode() { return stateCode; } public void setStateCode(int stateCode) { this.stateCode = stateCode; } }
package com.geeklicreed.observer; import java.util.Observable; import java.util.Observer; public class ConcreteObserver implements Observer { // 状态码应该和主题对象保持一致 private int stateCode; public int getStateCode() { return stateCode; } public void setStateCode(int stateCode) { this.stateCode = stateCode; } @Override public void update(Observable o, Object arg) { this.stateCode = ((ConcreteSubject)o).getStateCode(); } }
package com.geeklicreed.observer; public class Client { public static void main(String[] args) { ConcreteSubject concreteSubject = new ConcreteSubject(); ConcreteObserver concreteObserver1 = new ConcreteObserver(); ConcreteObserver concreteObserver2 = new ConcreteObserver(); ConcreteObserver concreteObserver3 = new ConcreteObserver(); concreteSubject.addObserver(concreteObserver1); concreteSubject.addObserver(concreteObserver2); concreteSubject.addObserver(concreteObserver3); concreteSubject.set(1000); System.out.println("======================================"); System.out.println(concreteObserver1.getStateCode()); System.out.println(concreteObserver2.getStateCode()); System.out.println(concreteObserver3.getStateCode()); /*输出结果为: ====================================== 1000 1000 1000*/ } }
4、开发中常见的场景:
- 聊天室程序的,服务器转发给所有客户端
- 网络游戏(多人联机对战)场景中,服务器将客户端的状态进行分发
- 邮件订阅
- Servlet 中,监听器的实现
- Android 中,广播机制
- 京东商城中,群发某商品的打折信息