观察者模式
定义:
定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主体对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。
例如:朋友圈点赞,这个时候你是观察者,这个信息就是被观察者,也就是主题对象,当这个信息被评论的时候,微信就会通知观察者,不需要你时时刻刻去盯着这个评论;此外,网站的比价降价提醒。
类型:
行为型
适用场景:
关联行为场景,建立一套触发机制。
优点:
观察者和被观察者之间建立一个抽象的耦合。
观察者模式支持广播通信。
缺点:
观察者之间有过多的细节依赖、提高时间消耗及程序复杂度。
使用要得当,要避免循环调用。
代码实现:
实现的场景:在一个网站课程上,同学提出一个问题,讲师监听这个课程的问题。
有一个课程:
- Course.java
package com.design.pattern.behavioral.observer;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 15:44
*/
public class Course {
private String courseName;
public Course(String courseName) {
this.courseName = courseName;
}
public String getCourseName() {
return courseName;
}
}
以及问题类:
- Question.java
package com.design.pattern.behavioral.observer;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 15:45
*/
public class Question {
private String userName;
private String questionContent;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getQuestionContent() {
return questionContent;
}
public void setQuestionContent(String questionContent) {
this.questionContent = questionContent;
}
}
接下来需要有讲师类:
- Teacher.java
package com.design.pattern.behavioral.observer;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 15:46
*/
public class Teacher {
private String teacherName;
public Teacher(String teacherName) {
this.teacherName = teacherName;
}
}
接下来,对于讲师,观察的是这个课程,而不是问题,问题属于课程。
让课程类继承java的Observable:
- Course.java
package com.design.pattern.behavioral.observer;
import java.util.Observable;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 15:44
*/
public class Course extends Observable {
private String courseName;
public Course(String courseName) {
this.courseName = courseName;
}
public String getCourseName() {
return courseName;
}
}
让Course可以被观察,在Observable中,添加、删除观察者等方法中使用synchronized修饰,实现线程安全。
之后,在课程类下创建生产问题的方法,进行通知:
- Course.java
package com.design.pattern.behavioral.observer;
import java.util.Observable;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 15:44
*/
public class Course extends Observable {
private String courseName;
public Course(String courseName) {
this.courseName = courseName;
}
public String getCourseName() {
return courseName;
}
public void produceQuestion(Course course, Question question) {
System.out.println(question.getUserName() + "在" + course.courseName + "提出了问题。");
// Observable提供的方法
setChanged();
notifyObservers(question);
}
}
对于观察者Teacher,需要实现Observer接口:
- Teacher.java
package com.design.pattern.behavioral.observer;
import java.util.Observable;
import java.util.Observer;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 15:46
*/
public class Teacher implements Observer {
private String teacherName;
public Teacher(String teacherName) {
this.teacherName = teacherName;
}
@Override
public void update(Observable o, Object arg) {
Course course = (Course) o;
Question question = (Question) arg;
System.out.println(teacherName + "老师的" + course.getCourseName()
+ "接收到" + question.getUserName() + "一个问题:" + question.getQuestionContent());
}
}
编写测试:
- Test.java
package com.design.pattern.behavioral.observer;
/**
* @Author: JLU Tiger
* @Date: 2019/9/5 16:01
*/
public class Test {
public static void main(String[] args) {
Course course = new Course("Java设计模式精讲");
Teacher teacher = new Teacher("Alpha");
// 添加观察者
course.addObserver(teacher);
// 业务逻辑,创建一个问题
Question question = new Question();
question.setUserName("Geely");
question.setQuestionContent("Java的主函数如何编写");
course.produceQuestion(course, question);
}
}
运行结果:
Geely在Java设计模式精讲提出了问题。
Alpha老师的Java设计模式精讲接收到Geely一个问题:Java的主函数如何编写
此外,对于观察者的update方法的实现,一旦并发过高,现在是同步的,我们需要使用消息队列等异步手段进行更改。
观察者模式在源码中的应用
比如我们写一个CS结构的软件,我们添加按钮,在鼠标点击的时候监听这个事件,即事件监听器。例如java.awt.Event,它的实现方式就是观察者模式。
在我们的web开发中,xml的Listener,Listener的上层RequestContextListener实现了ServletRequestListener,而ServletRequestListene又实现了util包下的EventListener接口。
在SpringFrameWork的ReaderEventListener也是继承了EventListener。