介绍
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种
它定义了一种 一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
理解
主播是被观察者,粉丝是观察者,当主播开播时,发通知给所有的粉丝(粉丝肯定是多个)
角色
Subject
主题,即:被观察者,Observable,一般是普通类 或 抽象类
把所有 观察者 保存在一个 集合 里,即:可以有任意数量的观察者,可以增加和删除观察者
主题的状态,就是 成员变量,一般是
boolean
类型通知方法,给所有观察者发送通知
什么是发通知?
答:就是 被观察者 调用 观察者(多个) 的某个方法
如何发通知?
答:状态发生改变后,发送通知给观察者
ConcreteSubject
具体的被观察者类,该类的状态发生改变时,给所有观察者发送通知。
Observer
观察者,一般是接口
至少有一个通知方法
ConcrereObserver
具体观察者,观察者实现类,实现观察者接口
通知方法:被观察者通知观察者时,其实就是调用该方法
java 内置观察者相关类
观察者:实现
java.util.Observer
接口,实现update()
方法,当 被观察者 通知 观察者时,会调用该方法被观察者类:需要继承
java.util.Observable
类addObserver()
方法添加观察者当被观察者发生了改变,就需要调用
setChanged()
方法,将标志变量changed
修改为true
使用
notifyObservers()
方法通知所有的观察者,即:调用 观察者的update()
方法。并将标志变量changed
置回原值false
关键:必须先调用setChanged()
方法,否则不会通知
例子
主播是被观察者,粉丝是观察者,当主播开播时,发通知给所有的粉丝
使用 java自带类实现
观察者实现类
粉丝是观察者
package 观察者.java自带类;
import 观察者.Fans;
import java.util.Observable;
import java.util.Observer;
public class FansImpl implements Observer {
private String name;
public FansImpl(String name) {
this.name = name;
}
// 被观察者发通知时,调用该方法
@Override
public void update(Observable o, Object msg) {
System.out.println(msg);
Zhubo zhubo = (Zhubo)o;
System.out.println(name+"说:不学了,看 "+zhubo.getName() + "直播");
}
}
被观察者类
主播是被观察者
package 观察者.java自带类;
import java.util.Observable;
/**
* 主播类,相当于被观察者
*/
public class Zhubo extends Observable {
private String name;
public Zhubo(String name) {
this.name = name;
}
/**
* 开播,也就是修改状态
*/
public void kaibo(){
// ※※※※必须先调用该方法,否则通知方法无效※※※
setChanged();
// 发通知
notifyObservers(name+"开播啦,快来呀!");
}
public String getName() {
return name;
}
}
测试类
package 观察者.java自带类;
import java.util.Observer;
public class Main {
public static void main(String[] args) {
Zhubo lilei = new Zhubo("李雷");
Observer hanmeimei = new FansImpl("韩梅梅");
Observer lili = new FansImpl("lili");
Observer lucy = new FansImpl("lucy");
lilei.addObserver(hanmeimei);
lilei.addObserver(lili);
lilei.addObserver(lucy);
System.out.println("观察者数量:"+lilei.countObservers());
lilei.kaibo(); // 开播
System.out.println("------------ 移除 lucy--------");
lilei.deleteObserver(lucy);
System.out.println("观察者数量:"+lilei.countObservers());
lilei.kaibo(); // 必须先开播,否则不会发送通知
lilei.notifyObservers();
}
}
执行结果:
观察者数量:3
李雷开播啦,快来呀!
lucy说:老娘不学了,看 李雷直播
李雷开播啦,快来呀!
lili说:老娘不学了,看 李雷直播
李雷开播啦,快来呀!
韩梅梅说:老娘不学了,看 李雷直播
------------ 移除 lucy--------
观察者数量:2
李雷开播啦,快来呀!
lili说:老娘不学了,看 李雷直播
李雷开播啦,快来呀!
韩梅梅说:老娘不学了,看 李雷直播
例子
主播是被观察者,粉丝是观察者,当主播开播时,发通知给所有的粉丝
完全自定义,可更好的理解细节
观察者接口
粉丝是观察者
package 观察者;
/**
* 粉丝接口(相当于观察者接口)
*/
public interface Fans {
/**
* 主播(被观察者)通知粉丝(被观察者),就是调用该方法
* @param zhubo
* @param msg
*/
public void jinZhiBoJian(Zhubo zhubo,String msg);
}
观察者实现类
package 观察者;
public class FansImpl implements Fans{
private String name;
public FansImpl(String name) {
this.name = name;
}
@Override
public void jinZhiBoJian(Zhubo zhubo, String msg) {
System.out.println(msg);
System.out.println(name+"说:老娘不学了,看 "+zhubo.getName() + "直播");
}
}
被观察者类
主播是被观察者
package 观察者;
import java.util.ArrayList;
import java.util.List;
/**
* 主播类,相当于被观察者
*/
public class Zhubo {
private String name;
/**
* 该集合保存粉丝(粉丝相当于观察者)
*/
private List<Fans> fansList = new ArrayList();
/**
* 是否开播(相当于被观察者中的状态)
*/
private boolean isKaibo = false;
public Zhubo(String name) {
this.name = name;
}
/**
* 添加粉丝(观察者)
* @param fans
*/
public void addFans(Fans fans){
fansList.add(fans);
}
/**
* 删除粉丝(观察者)
* @param fans
*/
public void removeFans(Fans fans){
fansList.remove(fans);
}
public void clearFans(){
fansList.clear();
}
/**
* 开播,也就是修改状态
*/
public void kaibo(){
this.isKaibo = true;
}
/**
* 停播,也就是重置状态为初始值
*/
public void tingbo(){
this.isKaibo = false;
}
public void noticeAll(){
// 开播(状态为true)时,才会发通知
if(!isKaibo){
return;
}
for(Fans item:fansList){
item.jinZhiBoJian(this,name+"开播啦,快来呀!");
}
tingbo();
}
public String getName() {
return name;
}
}
测试类
package 观察者;
public class Main {
public static void main(String[] args) {
Zhubo lilei = new Zhubo("李雷");
Fans hanmeimei = new FansImpl("韩梅梅");
Fans lili = new FansImpl("lili");
Fans lucy = new FansImpl("lucy");
lilei.addFans(hanmeimei);
lilei.addFans(lili);
lilei.addFans(lucy);
lilei.kaibo(); // 必须先开播,否则不会发送通知
lilei.noticeAll();
System.out.println("------------ 移除 lucy--------");
lilei.removeFans(lucy);
lilei.kaibo(); // 必须先开播,否则不会发送通知
lilei.noticeAll();
}
}
执行结果:
李雷开播啦,快来呀!
韩梅梅说:老娘不学了,看 李雷直播
李雷开播啦,快来呀!
lili说:老娘不学了,看 李雷直播
李雷开播啦,快来呀!
lucy说:老娘不学了,看 李雷直播
------------ 移除 lucy--------
李雷开播啦,快来呀!
韩梅梅说:老娘不学了,看 李雷直播
李雷开播啦,快来呀!
lili说:老娘不学了,看 李雷直播