当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。好比,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。java
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新。异步
观察者模式使用四个类 Subject(通用抽象基类,不包含状态)、ConcreteSubject(带特定状态的Subject)、Observer (通用接口,不包含状态)和 ConcreteObserver (带特定的Observer )。ide
Subject基类:主要做用是抽象了被观察目标的通用操做,好比添加观察者、删除观察者、通知全部的观察者。测试
package com.dotleo.observer; import java.util.ArrayList; import java.util.List; /** * 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口 * * @author LiuFei * @create 2017-12-03 19:53 */ public class Subject { // 用来保存注册的观察者对象 private List<Observer> observers = new ArrayList<Observer>(); // attach detach notifyObservers // 绑定观察者 public void attach(Observer observer) { observers.add(observer); } // 删除观察者 public void detach(Observer observer) { observers.remove(observer); } // 通知全部观察者 protected void notifyObServers() { for (Observer observer : observers) { observer.update(this); } } }
有了Subject(目标)后,须要特殊定制一个含有状态的目标供观察者“观察”this
ConcreteSubject:持有特定的状态subjectState
,并继承Subject基类,拥有绑定观察者、删除观察者、通知全部观察者的能力。code
package com.dotleo.observer; /** * 具体的目标对象,负责把有关状态存入到相应的观察者对象中 * * @author LiuFei * @create 2017-12-03 19:55 */ public class ConcreteSubject extends Subject { // 目标对象的状态 private String subjectState; public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; this.notifyObServers(); } }
观察者接口:提供了经过改变的目标去更新本身的状态server
package com.dotleo.observer; /** * 这是一个观察者接口,定义一个更新的接口给那些在目标发生变化的时候被通知的对象 * * @author LiuFei * @create 2017-12-03 19:58 */ public interface Observer { void update(Subject subject); }
观察者实例:实现了接口,拥有特定的状态,实现能够和目标同步的方法对象
package com.dotleo.observer; /** * 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致 * * @author LiuFei * @create 2017-12-03 19:59 */ public class ConcreteObserver implements Observer { // 观察者的状态 private String observerState; /** * 获取目标类的状态同步到观察类的状态中 * @param subject */ @Override public void update(Subject subject) { observerState = ((ConcreteSubject) subject).getSubjectState(); } }
黄明在气象站工做,他能第一时间获得天气预报,为了给女友和老妈贴心的提示,他打算写一个程序(他会写代码),在天天本身改变天气状态后,他的女友和老妈能收到提示:继承
因而他想到了观察者模式。接口
Subject基类:WeatherSubject
package com.dotleo.observer.weather; import java.util.ArrayList; import java.util.List; /** * 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口 * * @author LiuFei * @create 2017-12-03 19:53 */ public class WeatherSubject { // 用来保存注册的观察者对象 private List<Observer> observers = new ArrayList<Observer>(); // attach detach notifyObservers /** * 添加订阅天气的人 * @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); } } }
带有特定状态(天气)的Subject:ConcreteWeatherSubject
package com.dotleo.observer.weather; /** * 具体的目标对象,负责把有关状态存入到相应的观察者对象中 * * @author LiuFei * @create 2017-12-03 19:55 */ public class ConcreteWeatherSubject extends WeatherSubject { // 目标对象的状态 private String weatherContent; public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; this.notifyObServers(); } }
Observer接口:Observer
package com.dotleo.observer.weather; /** * 这是一个观察者接口,定义一个更新的接口给那些在目标发生变化的时候被通知的对象 * * @author LiuFei * @create 2017-12-03 19:58 */ public interface Observer { void update(WeatherSubject subject); }
带有特定状态(天气),信息(观察者姓名,提醒内容):ConcreteObserver
package com.dotleo.observer.weather; /** * 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致 * * @author LiuFei * @create 2017-12-03 19:59 */ public class ConcreteObserver implements Observer { // 观察者姓名,谁收到这个消息,黄明的女友或者老妈 private String observerName; // 天气状态,从目标处获取 private String weatherContext; // 提醒内容,黄明的女友提醒约会,而他老妈则提醒购物 private String remindThing; /** * 获取目标类的状态同步到观察类的状态中 * @param subject */ @Override public void update(WeatherSubject subject) { weatherContext = ((ConcreteWeatherSubject) subject).getWeatherContent(); System.out.println(observerName + "收到了" + weatherContext + "," + remindThing); } public String getObserverName() { return observerName; } public void setObserverName(String observerName) { this.observerName = observerName; } public String getWeatherContext() { return weatherContext; } public void setWeatherContext(String weatherContext) { this.weatherContext = weatherContext; } public String getRemindThing() { return remindThing; } public void setRemindThing(String remindThing) { this.remindThing = remindThing; } }
测试类:ObserverTest
package com.dotleo.observer.weather; /** * @author LiuFei * @create 2017-12-03 20:33 */ public class ObserverTest { public static void main(String[] args) { // 1. 建立一个目标 ConcreteWeatherSubject weatherSubject = new ConcreteWeatherSubject(); // 2. 建立观察者 ConcreteObserver concreteObserver1 = new ConcreteObserver(); concreteObserver1.setObserverName("黄明的女友"); concreteObserver1.setRemindThing("是咱们的第一次约会,地点街心公园,不见不散!"); ConcreteObserver concreteObserver2 = new ConcreteObserver(); concreteObserver2.setObserverName("黄明的老妈"); concreteObserver2.setRemindThing("是购物的好日子,明天去商城扫物!"); // 3. 注册观察者 weatherSubject.attach(concreteObserver1); weatherSubject.attach(concreteObserver2); // 4. 目标发布天气 weatherSubject.setWeatherContent("明每天气晴朗,蓝天白云,气温28度"); } }
运行结果
优势:
缺点:
在java.util包中包含有基本的Observer接口和Observable抽象类.功能上和Subject接口和Observer接口相似.不过在使用上,就方便多了,由于许多功能好比说注册,删除,通知观察者的那些功能已经内置好了。
Observer -- > Observer接口
Observable --> Subject基类
**ConcreteWeatherSubject **
package com.dotleo.observer.util; import java.util.Observable; public class ConcreteWeatherSubject extends Observable { private String weatherContent; public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; this.setChanged(); this.notifyObservers(); } }
**ConcreteObserver **
package com.dotleo.observer.util; import java.util.Observable; import java.util.Observer; /** * @author LiuFei * @create 2017-12-04 22:37 */ public class ConcreteObserver implements Observer { // 观察者姓名,谁收到这个消息,黄明的女友或者老妈 private String observerName; // 天气状态,从目标处获取 private String weatherContext; // 提醒内容,黄明的女友提醒约会,而他老妈则提醒购物 private String remindThing; public ConcreteObserver(String observerName, String weatherContext, String remindThing) { this.observerName = observerName; this.weatherContext = weatherContext; this.remindThing = remindThing; } @Override public void update(Observable o, Object arg) { weatherContext = ((ConcreteWeatherSubject ) o).getWeatherContent(); System.out.println(observerName + "收到了" + weatherContext + "," + remindThing); } }
**ObserverTest **
package com.dotleo.observer.util; import com.dotleo.observer.weather.ConcreteObserver; /** * @author LiuFei * @create 2017-12-04 22:43 */ public class ObserverTest { public static void main(String[] args) { // 1. 建立一个目标 com.dotleo.observer.weather.ConcreteWeatherSubject weatherSubject = new com.dotleo.observer.weather.ConcreteWeatherSubject(); // 2. 建立观察者 com.dotleo.observer.weather.ConcreteObserver concreteObserver1 = new com.dotleo.observer.weather.ConcreteObserver(); concreteObserver1.setObserverName("黄明的女友"); concreteObserver1.setRemindThing("是咱们的第一次约会,地点街心公园,不见不散!"); com.dotleo.observer.weather.ConcreteObserver concreteObserver2 = new ConcreteObserver(); concreteObserver2.setObserverName("黄明的老妈"); concreteObserver2.setRemindThing("是购物的好日子,明天去商城扫物!"); // 3. 注册观察者 weatherSubject.attach(concreteObserver1); weatherSubject.attach(concreteObserver2); // 4. 目标发布天气 weatherSubject.setWeatherContent("明每天气晴朗,蓝天白云,气温28度"); } }