前言:
现在我们生活中已经离不开微信, QQ 等交流软件, 这对于我们来说不仅是交流, 更有在朋友圈中或空间中进行分享自己的生活, 同时也可以通过这个渠道知道别人的生活. 我们在看朋友圈的时候其实我们扮演的就是一个观察者, 朋友圈或空间里的动态可以看作是主体对象. 接下来我们就介绍一下观察者模式
一, 定义
定义了对象之间的一对多依赖, 让多个观察者对象同时监听某一个主体对象, 当主体对象发生变化时, 它的所有观察者都会收到通知并更新.
二, 适用场景
1, 关联行为场景, 建立一套触发机制
这里稍微理解一下, 你有一个特别关心, 这个特别关心发消息, 发动态都会通知你, 发消息是一个行为, 通知你又是一个行为, 我们可以在观察者模式中建立一套触发机制, 当她发消息的时候就会通知你. 这就是关联行为和触发机制.
三, 观察者模式详解
本来是想结合 JDK 来讲的, 但是观察者模式在 JDK 中应用的更多是监听器, 主要用来做 C/S 架构的, 在实际中很少用. 但是 JDK 中会提供 Observable 类作为抽象被观察者, 而 Observer 作为抽象观察者接口. 所以这里就自己动手写一下观察者模式. 下面我们介绍观察者模式需要的角色:
1, 抽象观察者角色:
为所有的具体观察者定义一个接口, 在得到被观察者做出行为时通知更新自己.
2, 具体观察者角色:
实现抽象观察者角色所需要的更新接口, 并接受观察者的通知信息.
3, 抽象被观察者角色:
它把所有对观察者对象的引用保存在一个集合中, 每个主体都可以有任意数量的观察者. 抽象主体提供一个接口, 可以增加和删除观察者角色. 一般用一个抽象类和接口来实现.
4, 具体被观察者角色:
也就是一个具体的主体, 在主体的内部状态改变时, 向所有观察者发出通知.
由于 JDK 中已经自带了两个抽象角色, 所以就直接使用
- public class Observable {
- private boolean changed = false;
- private Vector<Observer> obs;
- public Observable() {
- obs = new Vector<>();
- }
- public synchronized void addObserver(Observer o) {
- if (o == null)
- throw new NullPointerException();
- if (!obs.contains(o)) {
- obs.addElement(o);
- }
- }
- public synchronized void deleteObserver(Observer o) {
- obs.removeElement(o);
- }
- public void notifyObservers() {
- notifyObservers(null);
- }
- public void notifyObservers(Object arg) {
- Object[] arrLocal;
- synchronized (this) {
- if (!changed)
- return;
- arrLocal = obs.toArray();
- clearChanged();
- }
- for (int i = arrLocal.length-1; i>=0; i--)
- ((Observer)arrLocal[i]).update(this, arg);
- }
- public synchronized void deleteObservers() {
- obs.removeAllElements();
- }
- protected synchronized void setChanged() {
- changed = true;
- }
- protected synchronized void clearChanged() {
- changed = false;
- }
- public synchronized boolean hasChanged() {
- return changed;
- }
- public synchronized int countObservers() {
- return obs.size();
- }
- }
上面是抽象被观察者角色 (不是抽象类或接口, 但在这里我们就这样理解), 可以看见这里面基本都是同步的容器, 方法, obs 主要是放观察者的. 因为继承这个类的子类是被观察者, 注意多个观察者是观察一个被观察者, 但是一个观察者可以观察多个被观察对象. 两个之间是多对多的关系, 我们现在主要先实现多个观察者观察一个被观察对象的情况
- public interface Observer {
- void update(Observable o, Object arg);
- }
上面是抽象观察者角色. 里面的 update 方法的意思是当被观察者做出一定行为后, 观察者就可以接受到一些消息. 但需要我们去实现具体监听的方式.
- import java.util.Observable;
- /**
- * 扮演被观察者具体实现类
- *created by Mr.F on 2019/4/14
- */
- public class Course extends Observable {
- private String courseName;
- public String getCourseName() {
- return courseName;
- }
- public void setCourseName(String courseName) {
- this.courseName = courseName;
- }
- public void produceQuestion(Course course,Question question){
- System.out.println(question.getStudentName()+"在"+course.courseName+"提了"+question.getQuestionContext());
- setChanged();// 改变被观察者的状态
- notifyObservers(question);
- }
- }
- // 被悲观者中的具体内容
- public class Question {
- private String questionContext;
- private String studentName;
- public String getStudentName() {
- return studentName;
- }
- public void setStudentName(String studentName) {
- this.studentName = studentName;
- }
- public String getQuestionContext() {
- return questionContext;
- }
- public void setQuestionContext(String questionContext) {
- this.questionContext = questionContext;
- }
- }
- import java.util.Observer;
- /**
- * 观察者具体实现类
- * created by Mr.F on 2019/4/14
- */
- public class Teacher implements Observer {
- private String teacherName;
- public String getTeacherName() {
- return teacherName;
- }
- public void setTeacherName(String teacherName) {
- this.teacherName = teacherName;
- }
- @Override
- public void update(java.util.Observable o, Object arg) {
- Course course= (Course) o;// 强转被观察者对象
- Question question= (Question) arg;
- System.out.println(teacherName+"收到了来自"+course.getCourseName()+"的"+question.getQuestionContext());
- }
- }
上面的代码不多说, 可以看注释, 主要是一个 Teacher 类作为观察者, Course 类作为被观察者. 这里主要看 Course 中的 produceQuestion 方法和 Teacher 中的 update 方法. 再去看上面抽象角色中的具体实现就能明白之间的调用, 这里简单说一下, 当将观察者添加进 Observable 中的 obs 数组的时候, 每次调用 produceQuestion 方法, 都能使得观察者中能得到信息.
- /**
- * created by Mr.F on 2019/4/14
- */
- public class Test {
- public static void main(String[] args) {
- Question question=new Question();
- question.setStudentName("方块人");
- question.setQuestionContext("观察者模式怎么写?");
- Course course =new Course();
- course.setCourseName("设计模式课堂");
- Teacher teacher1=new Teacher();
- Teacher teacher2=new Teacher();
- teacher1.setTeacherName("老师 1");
- teacher2.setTeacherName("老师 2");
- course.addObserver(teacher1);
- course.addObserver(teacher2);
- course.produceQuestion(course,question);
- }
- }
上面是测试类代码. 下面是输出结果:
四, 总结
其实每个观察者模式并不一定要像上面那样实现两个接口, 而是有很多方式, 不要学了模板, 忘了原理. 平常在做 web 项目的时候, 做点赞系统, 其实更多用的是观察者模式 + 生产者模式 + 消费者模式 + 异步队列. 为什么会用到上面这么多模式呢, 其实主要是考虑到并发的问题, 上面的 java 中自带的 Observable 是用锁的方式, 如果被观察者同时做了很多事情, 这里我们可以用异步队列来进行处理后期的行为. 观察者模式核心就是当被观察者做出行为的时候, 观察者一定会进行更新. 一定要多看上面那两个接口是如何调用的.
来源: https://www.cnblogs.com/Cubemen/p/10708107.html