文章目录
观察者模式
一、什么是观察者模式
观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。
对于观察者模式而言,肯定有观察者和被观察者之分。比如在一个目录下建立一个文件,这时系统会通知目录管理器增加目录,并通知磁盘减少空间,在这里,文件就是观察者,目录管理器和磁盘就是被观察者。
观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:
其中,Subject类是主题,它把所有对观察者对象的引用文件存在了一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供了一个接口,可以增加和删除观察者对象;Observer类是抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;ConcreteSubject类是具体主题,将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知;ConcreteObserver是具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协同。
二、观察者模式的应用
- 何时使用
- 一个对象状态改变,所有的依赖对象都将得到通知
- 方法
- 使用面向对象技术
- 优点
- 观察者和被观察者是抽象耦合的
- 建立了一套触发机制
- 缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果观察者和观察目标间有循环依赖,可能导致系统崩溃
- 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的
- 使用场景
- 关联行为场景
- 事件多级触发场景
- 跨系统的消息变换场景,如消息队列的处理机制
三、观察者模式的实现
1、类图
2、主题:Subject
package com.gykalc.jdk8.observer;
/**
* 主题,也就是被观察者
*/
public interface Subject {
/**
* 添加一个观察者
* @param observer
*/
void addObserver(Observer observer);
/**
* 移除一个观察者
* @param observer
*/
void removeObServer(Observer observer);
/**
* 通知所有观察者
*/
void notifyObServer();
}
3、抽象观察者:Observer
package com.gykalc.jdk8.observer;
/**
* 观察者
*/
public interface Observer {
void update(News news);
}
4、具体被观察者和被观察属性:CCTV1、News
package com.gykalc.jdk8.observer;
import java.util.ArrayList;
import java.util.List;
public class CCTV1 implements Subject {
private List<Observer> observerList = new ArrayList<>();
private News news;
public News getNews() {
return news;
}
public void setNews(News news) {
this.news = news;
}
@Override
public void addObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObServer(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObServer() {
observerList.stream().forEach(observer -> observer.update(news));
}
}
class News {
private String title;
private String msg;
public News(String title, String msg) {
this.title = title;
this.msg = msg;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "News{" +
"title='" + title + '\'' +
", msg='" + msg + '\'' +
'}';
}
}
5、具体观察者:LiSi、ZhangSan、WangWu
package com.gykalc.jdk8.observer;
public class ZhangSan implements Observer {
@Override
public void update(News news) {
System.out.println("张三正在看:" + news.toString());
}
}
class LiSi implements Observer{
@Override
public void update(News news) {
System.out.println("李四正在观看:" + news.toString());
}
}
class WangWu implements Observer {
@Override
public void update(News news) {
System.out.println("王五正在观看:" + news.toString());
}
}
6、调用测试类:Client
package com.gykalc.jdk8.observer;
public class Client {
public static void main(String[] args) {
CCTV1 cctv1 = new CCTV1();
LiSi liSi = new LiSi();
ZhangSan zhangSan = new ZhangSan();
WangWu wangWu = new WangWu();
cctv1.addObserver(liSi);
cctv1.addObserver(zhangSan);
cctv1.addObserver(wangWu);
cctv1.setNews(new News("货拉拉长沙女子跳车", ".....新闻内容....."));
cctv1.notifyObServer();
cctv1.setNews(new News("头条头条", ".....骗你的....."));
cctv1.notifyObServer();
}
}