观察者模式定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者:Observer update()
被观察者(目标):Subject attach();Detach();notify()
1. 目标与观察者的关系:典型的一对多
2. 单向依赖:
3. 命名建议
4. 触发通知的时机:完成消息处理后触发通知
5. 观察者模式的调用顺序:创建目标对象,创建观察者对象,向目标对象注册观察者对象—>
改变目标对象的状态,通知所有被注册的观察者对象进行相应的处理
回调目标对象,获取相应的数据。
6. 通知的顺序:多个观察者互相平行,通知先后也都是平行的。
import java.util.ArrayList;
import java.util.List;
/**
* Created by dell on 2018/4/16.
* 天气目标对象,它知道有谁观察了它,并提供注册(添加)和删除观察者的接口
*/
public class WeatherSubject {
//用来保存注册的观察者对象
private List<WeatherObserver> observers = new ArrayList<>();
//attach 添加需要保存的观察者
//添加订阅天气信息的人
public void attach(WeatherObserver observer){
observers.add(observer);
}
//detach 删除之前保存的观察者
//删除集合中的指定了的订阅天气的人
public void detach(WeatherObserver observer){
observers.remove(observer);
}
//notifyObservers 通知所有注册的观察者对象
//把更新了的天气信息通知所有已经订阅天气信息的人
protected void notifyObservers(){
for (WeatherObserver observer:observers){
observer.update(this);
}
}
}
/**
* 具体的目标对象,负责把有关状态存入到相应的观察者对象中
* Created by dell on 2018/4/16.
*/
public class ConcreteWeatherSubject extends WeatherSubject {
//目标对象的状态 获取天气信息
private String weatherContent;
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//天气已经更新,通知订阅者更新天气
notifyObservers();
}
}
/**
* Created by dell on 2018/4/16.
* 观察者接口,定义更新的方法,给那些在目标发生改变时,需要被通知的对象
*/
public interface WeatherObserver {
/**
* 更新的接口 subject
* */
public void update(WeatherSubject subject);
}
import java.util.Observer;
/**
* 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
* Created by dell on 2018/4/16.
*/
public class ConcreteWeatherObserver implements WeatherObserver {
//观察者的名字
private String observerName;
//天气情况内容 从subject中获取
private String weatherContent;
// 提醒的内容
private String remindMsg;
//获取目标类的状态同步到观察者的状态中
@Override
public void update(WeatherSubject subject) {
weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent();
System.out.println(observerName+"收到了"+weatherContent+","+remindMsg);
}
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 getRemindMsg() {
return remindMsg;
}
public void setRemindMsg(String remindMsg) {
this.remindMsg = remindMsg;
}
}
public class Main {
public static void main(String[] args) {
//创建目标
ConcreteWeatherSubject weather = new ConcreteWeatherSubject();
//创建观察者
ConcreteWeatherObserver girl = new ConcreteWeatherObserver();
girl.setObserverName("喜欢逛街的女生");
girl.setRemindMsg("天气晴朗,可以逛街");
ConcreteWeatherObserver farmer = new ConcreteWeatherObserver();
farmer.setObserverName("等待下雨的农民");
farmer.setRemindMsg("天又晴了,快下雨吧");
//注册观察者
weather.attach(girl);
weather.attach(farmer);
//目标更新 观察者收到消息
weather.setWeatherContent("天气晴朗");
}
}
运行结果
喜欢逛街的女生收到了天气晴朗,天气晴朗,可以逛街
等待下雨的农民收到了天气晴朗,天又晴了,快下雨吧
Process finished with exit code 0
JDK提供的观察者模式
java.util.Observerable类和Observer接口
触发通知的方式:调用setChanged方法。
场景:有三位订阅者订阅了作家张三的博客。博客更新后会给订阅者发送消息,提醒订阅者去查看新的内容
import java.util.Observable;
import java.util.Observer;
/**
* Created by dell on 2018/4/17.
* 观察者/订阅者 实现Observer接口
*/
public class BlogReader implements Observer {
private String BlogReaderName;
public String getBlogReaderName() {
return BlogReaderName;
}
public void setBlogReaderName(String blogReaderName) {
BlogReaderName = blogReaderName;
}
private String BlogContent;
public String getBlogContent() {
return BlogContent;
}
public void setBlogContent(String blogContent) {
BlogContent = blogContent;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(getBlogReaderName()+"收到了博客更新消息,获得内容"+arg);
}
public void update(Observable o) {
System.out.println(getBlogReaderName()+"主动查看作者"
+(((Blog)o).getAuthorName()+"的更新内容"+((Blog)o).getBlogContent()));
}
}
import java.util.Observable;
/**
* Created by dell on 2018/4/17.
* 博客类 可以向订阅者发布更新 被观察的目标对象 继承Observable
*/
public class Blog extends Observable{
private String authorName;
private String blogContent;
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public Blog(String authorName) {
this.authorName = authorName;
}
public String getBlogContent() {
return blogContent;
}
public void setBlogContent(String blogContent) {
this.blogContent = blogContent;
//博客内容已经有了,说明博客更新了,提醒观察者
this.setChanged();
//主动通知
this.notifyObservers(blogContent);
this.notifyObservers();
}
}
客户端类
public class Main {
public static void main(String[] args) {
Blog blog = new Blog("张三");
blog.setBlogContent("博客更新啦");
BlogReader blogReader1 = new BlogReader();
blogReader1.setBlogReaderName("阅读者1");
BlogReader blogReader2 = new BlogReader();
blogReader2.setBlogReaderName("阅读者2");
BlogReader blogReader3 = new BlogReader();
blogReader3.setBlogReaderName("阅读者3");
blogReader1.update(blog,"更新");
blogReader2.update(blog);
blogReader3.update(blog);
}
}
运行结果
阅读者1收到了博客更新消息,获得内容更新
阅读者2主动查看作者张三的更新内容博客更新啦
阅读者3主动查看作者张三的更新内容博客更新啦
Process finished with exit code 0
观察者模式的使用场景:1.当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化。2.如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变。3.当一个对象必须通知其他的对象,例如手机电量不足,又希望这个对象和其他被通知的对象之间是松散耦合的。
区别对待观察者场景问题:
需求1,博客包含很多系列,读者1只关心android系列,读者2只关心java系列,读者3两个系列都关心。
需求2,博客更新android系列,读者1和读者3收到消息,做出不同反应。博客更新java系列,读者2和读者3收到消息,做出不同反应。
需求3,博客更新情感系列,不发送消息。
package com.company;
import java.util.ArrayList;
import java.util.Observable;
/**
* Created by dell on 2018/4/17.
*/
public abstract class BlogWithTag extends Observable{
public ArrayList<BlogReader> blogReaders = new ArrayList<>();
public void attach(BlogReader blogReader){
blogReaders.add(blogReader);
}
public void detach(BlogReader blogReader){
blogReaders.remove(blogReader);
}
public abstract void notifyReaders();
}
package com.company;
import java.util.Observable;
/**
* Created by dell on 2018/4/17.
* 博客类 可以向订阅者发布更新
*/
public class Blog extends BlogWithTag {
//作者姓名
private String authorName;
private ArticleInfo articleInfo;
public ArticleInfo getArticleInfo() {
return articleInfo;
}
public void setArticleInfo(ArticleInfo articleInfo) {
this.articleInfo = articleInfo;
this.notifyReaders();
}
public String getAuthorName() {
return authorName;
}
public Blog(String authorName) {
this.authorName = authorName;
}
@Override
public void notifyReaders() {
for (BlogReader blogReader : blogReaders) {
if (this.articleInfo.getTag().equals("java")) {
if (blogReader.getBlogReaderName().equals("reader1") || blogReader.getBlogReaderName().equals("reader3")) {
blogReader.update(this,"java");
}
}
if (this.articleInfo.getTag().equals("android")) {
if (blogReader.getBlogReaderName().equals("reader2") || blogReader.getBlogReaderName().equals("reader3")) {
blogReader.update(this);
}
}
}
}
}
package com.company;
import java.util.Observable;
import java.util.Observer;
/**
*
* Created by dell on 2018/4/17.
* 重写update方法
*/
public class BlogReader implements Observer {
private String blogReaderName;
private String blogTag;
private String remindBlog;
public String getBlogReaderName() {
return blogReaderName;
}
public BlogReader(String blogReaderName) {
this.blogReaderName = blogReaderName;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(getBlogReaderName()+"收到了博客更新消息,获得内容"+arg);
}
public void update(Observable o) {
Blog blog = (Blog)o;
this.blogTag = ((Blog) o).getArticleInfo().getTag();
if (blogTag == "java"){
System.out.println(((Blog) o).getArticleInfo().getContent()+((Blog) o).getArticleInfo().getTag());
System.out.println("java系列博客更新,去学习");
}
if (blogTag == "android"){
System.out.println(((Blog) o).getArticleInfo().getContent()+((Blog) o).getArticleInfo().getTag());
System.out.println("android系列博客更新,去实践");
}
}
}
package com.company;
/**
* 需求1,博客包含很多系列,读者1只关心android系列,读者2只关心java系列,读者3两个系列都关心。
需求2,博客更新android系列,读者1和读者3收到消息,做出不同反应。博客更新java系列,读者2和读者3收到消息,做出不同反应。
需求3,博客更新情感系列,不发送消息。
实现步骤:定义目标的抽象类和观察者的接口
实现目标的类和观察者接口
* */
public class Main {
public static void main(String[] args) {
Blog blog = new Blog("Cindy");
BlogReader blogReader1 = new BlogReader("reader1");
BlogReader blogReader2 = new BlogReader("reader2");
BlogReader blogReader3 = new BlogReader("reader3");
ArticleInfo articleInfo1 = new ArticleInfo("java 很好用","java");
ArticleInfo articleInfo2 = new ArticleInfo("你会用activity么","android");
ArticleInfo articleInfo3 = new ArticleInfo("broadcastReceiver 详解","android");
blog.setArticleInfo(articleInfo1);
blogReader1.update(blog);
blog.setArticleInfo(articleInfo2);
blogReader2.update(blog);
blog.setArticleInfo(articleInfo3);
blogReader3.update(blog);
}
}
运行结果
java 很好用java
java系列博客更新,去学习
你会用activity么android
android系列博客更新,去实践
broadcastReceiver 详解android
android系列博客更新,去实践
.