标签:strong 用户 形式 pre 介绍 stat sys 报纸 比较
很久很久之前,我们获知世界大事都是要通过报纸的。而报社的业务就是出版报纸,向某家报社订阅报纸,只要他们有新报纸出版,就会给你送过来。当你不想再看报纸时,取消订阅,他们就不会再送新报纸过来了。
再比如,你在B站上关注了一个UP主,只要他一更新视频,你就会收到他的更新通知。不想再看时,则可以取关。
上面两种场景中体现的便是典型的观察者模式,这些场景主要分为两种角色,一种是发行报纸/更新视频的角色, 另一种则是订阅报纸/订阅更新的角色。前一种角色我们称之为主题(Subject),而后一种角色我们称之为观察者(Observer)。
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
解释一下:在现实世界中,许多对象并不是独立存在。一个主题对象状态发生变化时,许多依赖于该对象的其他观察者对象都需要发生变化。我们在类中可以模拟实现这种一对多依赖关系。具体做法是,当主题对象(Subject)内部的变量发生变化,它就去主动通知依赖于自己的所有观察者对象(Observer)。观察者模式可以将观察者和被观察的对象分离开,实现了两者之间的松耦合。
1. 抽象主题(Subject):
把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2. 具体主题(ConcreteSubject):
将有关状态变量存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出更新通知。
3. 抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4. 具体观察者(ConcreteObserver):
实现抽象观察者所定义的更新接口,以便主题对象在状态更新时通知观察者对象。
实现观察者模式有很多形式,比较常用的是使用“注册—通知—撤销注册”的方法。
具体做法是:主题对象维护一个内部状态字段和一个观察者列表,当主题对象的状态发生变化时,依次通知列表中的观察者。同时,观察者维护一个主题对象的引用,主要是实现从主题对象中进行主题以及撤销注册的操作。
好的!经过上面的许多介绍,相信大家都已经对观察者模式有所了解了,那么现在我们就开始实战一下!
具体场景是做一个B站UP主更新视频时,将更新信息推送到所有关注该UP主的用户上。
备注:我个人喜欢在接口名前加大写I(表示Interface),个人习惯,不喜勿喷!
第一步:定义抽象主题接口(ISubject接口)
/***
* 抽象主题接口
*/
public interface ISubject {
// 注册观察者
void registerObserver(IObserver observer);
// 移除观察者
void removeObserver(IObserver observer);
// 通知观察者
void notifyObservers();
// 更新内部状态
void updateVideo(String videoName);
}
第二步:定义具体的主题类(UpLoader类)
import java.util.ArrayList;
import java.util.List;
public class UpLoader implements ISubject {
private List<IObserver> observers; // 维护一个观察者列表,用来实现通知操作
private String videoName; // 维护一个内部状态,当更新视频时,videoName会发生变化
/**
* 构造器,用来初始化observers和videoName
*/
public UpLoader() {
this.observers = new ArrayList<>();
this.videoName = null;
}
/**
* uploader更新视频
* @param videoName
*/
public void updateVideo(String videoName) {
this.videoName = videoName;
notifyObservers(); // 通知所有的用户(观察者)
}
/**
* 用户(观察者)注册到该UpLoader上
* @param observer
*/
@Override
public void registerObserver(IObserver observer) {
observers.add(observer); // 添加到观察者列表上
}
/**
* 移除观察者
* @param observer
*/
@Override
public void removeObserver(IObserver observer) {
observers.remove(observer);
}
/**
* 通知所有的观察者
*/
@Override
public void notifyObservers() {
for (IObserver observer : observers) {
observer.update(videoName); // 通知用户(观察者)视频更新了
}
}
}
第三步:定义抽象观察者接口(IObserver接口)
public interface IObserver {
// 用来通知观察者主题状态发生更新
void update(String videoName);
// 取消关注主题对象
void removeUpLoader();
}
第四步:定义具体的用户观察者类(UserObserver类)
public class UserObserver implements IObserver {
private ISubject uploader; // 绑定的UP主
private String username; // 用户名
/**
* 构造器
* @param uploader
* @param username
*/
public UserObserver(ISubject uploader, String username) {
this.uploader = uploader;
this.username = username;
uploader.registerObserver(this); // 关注Up主
}
/**
* 通知该用户视频更新了
* @param videoName
*/
@Override
public void update(String videoName) {
System.out.println("奥力给!" + username + ",您关注的UP主更新视频了,视频名为:" + videoName + ",快去一键三连吧~~~");
}
/**
* 把Up主取消关注
*/
public void removeUpLoader() {
this.uploader.removeObserver(this);
}
}
第五步:功能测试(ObserverTest类)
public class ObserverTest {
public static void main(String[] args) {
// 构造一个UP主(主题)
ISubject uploader = new UpLoader();
// 建立三个用户(观察者)
IObserver user1 = new UserObserver(uploader, "小明");
IObserver user2 = new UserObserver(uploader, "小浩");
IObserver user3 = new UserObserver(uploader, "小志");
// up主第一次更新视频
uploader.updateVideo("小猪佩奇");
System.out.println("--------------------------------------------------------------------");
// user2小浩取消关注up主
user2.removeUpLoader();
// up主第二次更新视频
uploader.updateVideo("喜洋洋与灰太狼");
}
}
测试结果:
观察者模式使用到的设计原则:(来源于《Head First 设计模式》)
为了交互对象之间的松耦合而努力。
主题对象无需知道观察者的具体细节,只知道观察者实现了Observer接口。
松耦合降低了主题和观察者对象之间的相互依赖,一方代码的改变不会影响另一方。
找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
在观察者模式中,会变化的地方是主题的状态,以及观察者的数目和类型。当观察者的数目和类型发生变化时,并不会影响主题对象。
针对接口编程,而不是针对实现编程。
观察者可以利用主题的接口向主题注册以及注销,而主题利用观察者接口通知观察者。
多用组合,少用继承。
观察者模式将观察者列表组合进主题中,将主题组合进观察者中。
使用场景:
优缺点:
补充:
Java API也有内置的观察者模式
java.util包中包含最基本的Observer接口与Observable类,它就相当于我们上面定义的Observer接口与Subject接口。但要注意的是Observable(被观察者)是一个类而不是接口,这限制了它的复用能力。
观察者模式和发布-订阅模式的区别
正如我上面在具体实现中提到的那样,发布订阅模式是最常用的一种观察者模式的实现。发布订阅模式里,发布者和订阅者,不是松耦合,而是完全解耦的。他们通过一个中间人Broker进行交互。如下图所示:
好了,观察者模式的介绍就到此为止了,它的设计方式也比较简单,相信大家肯定已经完全了解了它的使用方法。
最后,希望本文能给大家带来帮助,谢谢!
参考文章:https://www.runoob.com/design-pattern/observer-pattern.html
标签:strong 用户 形式 pre 介绍 stat sys 报纸 比较
原文地址:https://www.cnblogs.com/yimeixiaobai1314/p/14695849.html