根据慕课网视频整理,视频地址 http://www.imooc.com/note/415
什么是观察者模式?
对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式的组成?
订阅者(subject)和观察者(observer)观察者模式优缺点?
优点
观察者模式实现了观察者和目标之间的抽象耦合
观察者模式实现了动态联动(所谓联动是指做一个操作会引起其它相关的操作)
观察者模式支持广播通信
缺点
可能会引起无谓的操作如何自己写方法实现?
观察者对象创建个实例传递给订阅者,当订阅者状态变化时,直接修改观察者实例。
下面看代码如何实现的
- 1.编写WeatherSubject类
package com.myimooc.designpattern.c5observer.weather;
import java.util.ArrayList;
import java.util.List;
/**
* @describe 管理订阅者列表
* @author zc
* @version 1.0 2017-08-29
*/
public class WeatherSubject {
/**
* 订阅者列表
*/
private List<Observer> observers = new ArrayList<Observer>();
/**
* 把订阅天气的人增加到订阅者列表中
*/
public void attach(Observer observer){
observers.add(observer);
}
/**
* 删除订阅的人
*/
public void detach(Observer observer){
observers.remove(observer);
}
/**
* 通知所有已经订阅天气的人
*/
protected void notifyObserver() {
observers.forEach(observer ->{
observer.update(this);
});
}
}
- 2.编写ConcreteWeatherSubject类
package com.myimooc.designpattern.c5observer.weather;
/**
* @describe 具体的目标对象,负责把有关状态存入到相应的观察者对象中
* @author zc
* @version 1.0 2017-08-29
*/
public class ConcreteWeatherSubject extends WeatherSubject {
/**
* 获取天气的内容信息
*/
private String weatherContent;
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
// 内容有了,说明天气更新了,通知所有订阅的人
this.notifyObserver();
}
}
- 3.编写Observer类
package com.myimooc.designpattern.c5observer.weather;
/**
* @describe 观察者接口,定义一个更新的接口给那些在目标对象发生改变的时候被通知的对象
* @author zc
* @version 1.0 2017-08-29
*/
public interface Observer {
/**
* 更新的接口
* @param subject 传入的目标对象,方便获取相应的目标对象的状态
*/
void update(WeatherSubject subject);
}
- 4.编写ConcreteObserver类
package com.myimooc.designpattern.c5observer.weather;
/**
* @describe 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
* @author zc
* @version 1.0 2017-08-29
*/
public class ConcreteObserver implements Observer {
/**
* 观察者的名称,是谁收到了这个信息
*/
private String observerName;
/**
* 天气的内容信息,这个消息从目标处获取
*/
private String weatherContent;
/**
* 提醒的内容,不同的观察者提醒不同的内容
*/
private String remindThing;
/**
* 获取目标类的状态同步到观察者的状态中
*/
@Override
public void update(WeatherSubject subject) {
weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent();
System.out.println(observerName + " 收到了天气信息 " + weatherContent + ",准备去做 "+remindThing);
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
}
public String getRemindThing() {
return remindThing;
}
public void setRemindThing(String remindThing) {
this.remindThing = remindThing;
}
}
- 5.编写Client类
/**
1. @describe 订阅天气-测试类
2. @author zc
3. @version 1.0 2017-08-29
*/
public class Client {
public static void main(String[] args) {
// 1.创建目标
ConcreteWeatherSubject weather = new ConcreteWeatherSubject();
// 2.创建观察者
ConcreteObserver observerGiel = new ConcreteObserver();
observerGiel.setObserverName("黄明的女朋友");
observerGiel.setRemindThing("是我们的第一次约会,地点街心公园,不见不散哦");
ConcreteObserver observerMum = new ConcreteObserver();
observerMum.setObserverName("老妈");
observerMum.setRemindThing("是一个购物的好日子,明天去天虹扫货");
// 3.注册观察者
weather.attach(observerGiel);
weather.attach(observerMum);
// 4.目标发布天气
weather.setWeatherContent("明天 天气晴朗,蓝天白云,气温28℃");
}
}
- 利用Java自带的Observable类实现
触发通知的方式有一点变化,要先调用setChanged方法,这是为了实现更精确的触发控制具体观察者的实现里面,update方法能同时支持推模型和拉模型,推模型是指把整个对象传给观察者,拉模型指的是把部分值传给观察者。
代码编写
- 1.编写ConcreteWeatherSubject类
package com.myimooc.designpattern.c5observer.weatherjdk;
import java.util.Observable;
/**
* @describe 使用JDK实现观察者模式,天气目标具体实现类
* @author zc
* @version 1.0 2017-08-29
*/
public class ConcreteWeatherSubject extends Observable {
/** 天气情况的内容 */
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
// 天气情况有了,就要通知所有的观察者
// 在用Java中的Observer模式时,需要先调用setChanged方法
this.setChanged();
// 调用通知方法-推模型
this.notifyObservers(content);
// 调用通知方法-拉模型
// this.notifyObservers();
}
}
- 2.编写ConcreteObserver类
package com.myimooc.designpattern.c5observer.weatherjdk;
import java.util.Observable;
import java.util.Observer;
/**
* @describe 使用JDK实现观察者模式,具体的观察者对象
* @author zc
* @version 1.0 2017-08-29
*/
public class ConcreteObserver implements Observer {
/** 观察者的名称,是谁收到了这个信息 */
private String observerName;
@Override
public void update(Observable o, Object arg) {
// 推模型
System.out.println(observerName + " 收到了消息,目标推送过来的是 "+arg);
// 拉模型
ConcreteWeatherSubject concreteWeatherSubject = (ConcreteWeatherSubject)o;
System.out.println(observerName + " 收到了消息,主动到目标对象中去拉 "+concreteWeatherSubject.getContent());
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
}
- 3.编写Client类
package com.myimooc.designpattern.c5observer.weatherjdk;
/**
* @describe 使用JDK实现观察者模式,测试类
* @author zc
* @version 1.0 2017-08-29
*/
public class Client {
public static void main(String[] args) {
// 创建天气作为一个目标,也可以说是被观察者
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
// 创建黄明的女朋友作为观察者
ConcreteObserver observerGiel = new ConcreteObserver();
observerGiel.setObserverName("黄明的女朋友");
// 创建黄明的老妈作为观察者
ConcreteObserver observerMum = new ConcreteObserver();
observerMum.setObserverName("老妈");
// 注册观察者
subject.addObserver(observerGiel);
subject.addObserver(observerMum);
// 目标更新天气情况
subject.setContent("明天 天气晴朗,蓝天白云,气温28℃");
}
}