一:什么是观察者模式:
官方定义:定义对象间一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
举个例子,很多人都会订阅天气预报,当气象台获得明天的天气情况(目标对象)时,就会短信通知订阅了天气预报的人(观察者),然后订阅者就会根据明天天气情况做出相应的处理(呆在家?出去踏青?出去购物...)
二:观察者模式的两个角色:
第一个角色:目标对象(subject),被观察者关注的对象,它的改变引起观察者的改变,例如上面提到的天气情况。
第二个角色:观察者(observer),一个或者多个,关注着目标对象的状态,例如上例的订阅了天气预报的人群。
三:观察者模式三种常见的角色场景:
1. 一个目标对象,一个观察者对象,比如只要你一个人订阅了天气预报
2. 一个目标对象,多个观察者对象,比如,你爸爸,你妈妈和你都订阅了天气预报
3. 多个目标对象,一个观察者对象,比如你一个人订阅了天气预报,还订阅了报纸
四:推模型和拉模型(后面的代码会有注释):
推模型:observer在执行update()方法时,获取的是subject传给它的具体参数,目标对象主动向观察者推送目标的详细信息。
拉模型:observer在执行update()方法时,获得的是subject传给它的一个subject对象,observer需要什么参数自己去取。
五:java代码实行观察者模式:
首先提供最基本的观察者模式代码框架:
1. 新建一个Subject父类
import java.util.ArrayList; import java.util.List; /* * 目标对象,他知道观察它的观察者,并提供注册(添加)和删除观察者的接口 */ public class Subject { //用来保存注册的观察者对对象 private List<Observer> observers = new ArrayList<Observer>(); //将观察者添加多list对象中 public void attch(Observer observer){ observers.add(observer); } //删除集合中的指定观察者对象 public void delete(Observer observer){ observers.remove(observer); } //向所有注册了的观察者通知消息 protected void notifyObserver() { for(Observer observer:observers){ observer.update(this); } } }
2. 新建一个具体Subject实现类
/* * 具体的目标对象,负责把有关状态存入到相应的观察者对象 */ public class ConcreteSubject extends Subject { //目标对象的状态 private String subjectState; public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; this.notifyObserver(); } }
3. 新建一个Observer接口
/* * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时,被通知的对象 */ public interface Observer { /* * 更新接口 * subject传入的目标对象,方便获取目标对象的状态 */ public void update(Subject subject); }
4. 新建一个observer实现类
/* * 具体的观察者对象,实现更新的方法,使自身状态和目标状态一致 */ public class ConcreteObserver implements Observer { private String observerState; @Override public void update(Subject subject) { // TODO Auto-generated method stub observerState = ((ConcreteSubject)subject).getSubjectState(); } }
下面我用一个具体的例子,来实现观察者模式,让你更加清晰了解观察者模式
一个这样的场景,小东的女朋友和老妈都订阅了小东开发的一个天气预报软件,当每天天气不同时,小东的女朋友和老妈收到天气情况通知,都会安排明天的行程。小东的这个软件可逗的女朋友和老妈开心了,原来程序猿还有这作用,下面来看程序如何演示的:
1. 新建一个WeatherSubject父目标对象
import java.util.ArrayList; import java.util.List; /* * 目标对象,他知道观察它的观察者,并提供注册(添加)和删除观察者的接口 */ public class WeatherSubject { //用来保存订阅天气的人 private List<Observer> observers = new ArrayList<Observer>(); //把订阅天气的人添加到订阅列表中 public void attch(Observer observer){ observers.add(observer); } //删除集合中的指定的订阅天气的人 public void delete(Observer observer){ observers.remove(observer); } //通知所有已经订阅了天气的人 protected void notifyObserver() { for(Observer observer:observers){ observer.update(this); } } }
2. 新建一个WeatherSubject具体实现对象( 观察者需要从目标对象中需要获取的的状态只有天气内容)
/* * 具体的目标对象,负责把有关状态存入到相应的观察者对象 */ 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接口
/* * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时,被通知的对象 */ public interface Observer { /* * 更新接口 * subject传入的目标对象,方便获取目标对象的状态 */ public void update(WeatherSubject subject); }
4. 新建一个具体的WeatherSubject对象
/* * 具体的观察者对象,实现更新的方法,使自身状态和目标状态一致 */ public class ConcreteObserver implements Observer { //观察者的名字,是谁收到了这个讯息,小东女朋友还是他老妈 private String observerName; //天气内容的情况,这个消息从目标处获得 private String weatherContent; //提醒的内容,小东的女朋友提醒约会,而他老妈提醒购物 private String 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; } public void update(WeatherSubject subject) { weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent(); System.out.println(observerName + "收到了" + weatherContent + ","+remindThing); } }
5. 测试类
public class Client { public static void main(String[] args) { //1.创建目标 ConcreteWeatherSubject weatherSubject = new ConcreteWeatherSubject(); //2.创建观察者 ConcreteObserver observerGirl = new ConcreteObserver(); observerGirl.setObserverName("小东的女朋友"); observerGirl.setRemindThing("是我们的第一次约会,地点华罗利广场,不见不散额"); ConcreteObserver observerMom = new ConcreteObserver(); observerMom.setObserverName("小东的老妈"); observerMom.setRemindThing("是一个购物的好日子,明天去老街血拼"); //3.注册观察者 weatherSubject.attch(observerGirl); weatherSubject.attch(observerMom); //4.目标发布天气 weatherSubject.setWeatherContent("明天天气晴朗,晴空万里,温度28℃"); } }
6. 运行结果
各位程序猿屌丝们,原来观察者模式还能来泡妞,你还等什么了,现在对观察者模式有了基本的了解了吧。最后我们来谈谈哪些情况能用到观察者模式:
- 当一个抽象模型有两个方面,其中一个方面的操作依赖与另一方面的状态变化就可以使用观察者模式。
- 如果在更改一个状态的时候,需要同事连带改变其他对象,而且不知道有多少个对象需要被连带改变时,可以选用观察者模式。
- 当一个对象必须通知其它对象,但你又希望这个对象和其它被它通知的对象是松散耦合的,也可以使用观察者模式。
谢谢各位看官的赏脸,我们下次再见!