观察者模式
B站视频链接:https://www.bilibili.com/video/BV1Ui4y1x7XT/
观察者模式的定义
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
场景
--聊天室程序的创建。服务器创建好后, A,B,C三个客户端连.上来公开聊天。A向服务器发送数据,服务器端聊天数据改变。我们希望将这些聊天数据分别发给其他在线的客户。也就是说,每个客户端需要更新服务器端得数据。
--网站上,很多人订阅了”java主题”的新闻。当有这个主题新闻时,就会将这些新闻发给所有订阅的人。
--大家一起玩CS游戏时,服务器需要将每个人的方位变化发给所有的客户。
上面这些场景,我们都可以使用观察者模式来处理。我们可以把多个订阅者、客户称之为观察者;需要同步给多个订阅者的数据封装到对象中,称之为目标。
核心:消息发布
--观察者模式主要用于1 : N的通知。当一个对象(目标对象Subject或Objservable)的状态变化时,他需要及时告知一系列对象(观察者对象,Observer) ,令他们做出响应。
--通知观察者的方式:消息订阅
●推
--每次都会把通知以广播方式发送给所有观察者,所有观察者只能被动接收。
●拉
--观察者只要知道有情况即可。至于什么时候获取内容,获取什么内容,都可以自主决定。
四个角色
抽象主题角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体主题角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
UML类图

举例:实现消息推送给订阅了的观察者,没有订阅的观察者无法收到消息推送。
抽象主题类和观察者抽象接口
package Observer;
/**
* 定义抽象主题
* @author 唐磊
*
*/
public abstract class Subject {
abstract void registerObserver(Observer obs);//添加Observer方法
abstract void removeObserver(Observer obs) ;//移除Observer方法
//通知所有观察者更新状态
abstract void notifyAllObservers() ;
}
package Observer;
/**
* 定义观察者抽象接口
* @author 唐磊
*
*/
public interface Observer {
void update(Subject subject);
}
具体主题和具体的观察者
package Observer;
import java.util.ArrayList;
/**
* 定义具体主题类
* @author 唐磊
*
*/
public class ConcreteSubject extends Subject{
private String message;
//存放观察者的容器
ArrayList<Observer> list = new ArrayList<Observer>();
public String getMessage() {
return message;
}
//目标对象的状态发生了变化,通知所有的观察者
public void setMessage(String message) {
this.message = message;
System.out.println("QQ推送了更新消息:"+message);
this.notifyAllObservers();
}
@Override
void registerObserver(Observer obs) {
list.add(obs);
}
@Override
void removeObserver(Observer obs) {
list.remove(obs);
}
@Override
void notifyAllObservers() {
for (Observer obs : list) {
obs.update(this);
}
}
}
package Observer;
/**
* 定义观察者具体类
* @author 唐磊
*
*/
public class ConcreteObserver implements Observer{
private String name;
private String myMessage;//观察者订阅的目标对象的message
public ConcreteObserver(String name){
this.name = name;
}
@Override
public void update(Subject subject) {
myMessage = ((ConcreteSubject)subject).getMessage();
read();
}
public void read() {
System.out.println(name+"收到了推送消息:"+myMessage);
}
public String getMyMessage() {
return myMessage;
}
public void setMyMessage(String myMessage) {
this.myMessage = myMessage;
}
}
Client
package Observer;
public class Client {
public static void main(String[] args) {
//目标对象
ConcreteSubject subject = new ConcreteSubject();
//创建多个观察者
ConcreteObserver obs1 = new ConcreteObserver("Lisa");
ConcreteObserver obs2 = new ConcreteObserver("James");
ConcreteObserver obs3 = new ConcreteObserver("Mary");
//将这些观察者加入Subject的Observer容器中
subject.registerObserver(obs1);
subject.registerObserver(obs2);
subject.registerObserver(obs3);
//改变subject目标对象的状态,设置推送消息
subject.setMessage("新冠疫情发布!");
System.out.println("----------------------------------");
subject.removeObserver(obs1);//Lisa取消了订阅
System.out.println("Lisa取消了订阅。");
subject.setMessage("美国新冠确诊人数突破100万人!!!");
}
}
运行结果

可以看到lisa取消订阅后,无法收到消息推送。

浙公网安备 33010602011771号