一、概念
1、定义:一(主题对象)对多(观察者对象)中,主题对象发生变化时,及时通知观察者进行更新,观察者可以订阅/取消订阅主题对象
2、类型:行为型
3、适用场景:关联行为场景,建立一套链式触发机制(触发链条,A通知B,B通知C)
4、优缺点
优点
- 观察者与被观察者之间建立了一个抽象的耦合,不管是增加观察者还是被观察者,都很容易扩展
- 观察者模式支持广播通信
缺点
- 观察者之间细节依赖太多,增加程序复杂度(比如触发链条)
- 要避免循环调用,可能导致系统崩溃
5、UML
观察者模式提供了一种对象设计,让主题和观察者之间低耦合,主题只知道观察者实现了Observer接口,主题不需要知道观察者的具体类是谁(因为所有观察者实现了相同的Obsever接口这是主题知道的,每个观察者都有一个update方法),做了什么,并且任何时候都能增删观察者,也不用改动主题的代码,主题只继承Observable抽象类,它只会给所有实现观察者接口的具体对象发送通知。改变其中一方并不会影响另一方,因为是松耦合的。
HeadFirst中提到另一个缺点是:主题继承了Observerable类,这是一个类,这个类甚至没有实现接口,那么就是不太符合针对接口编程设计原则的。一个主题类去继承它,如果这个类想拥有Observerable类和其他超类的行为,就不行,因为java不支持多重继承,这样就限制了Observerable类的复用。
二、代码实现
主题对象 也就是被观察的 Course
//course继承Observable类,成为被观察对象
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.getCourseName()+"提交了一个问题");
//setChanged()是Observable类提供的方法,代表状态发生了改变
setChanged(); // changed = true;需要调用它使得通知开始运转,另外也有一个hasChanged()方法来获得当前change标志的状态
//notifyObservers可传参也可以不传,这里把具体的问题传过去
notifyObservers(question);
}
}
观察者 Teacher
//老师观察的是课程而不是问题,问题是属于课程的
//观察者是teacher,被观察者是course(主题对象)
//teacher来实现Observer接口,这个接口只有update一个方法
public class Teacher implements Observer {
private String teacherName;
public Teacher(String teacherName) {
this.teacherName = teacherName;
}
/**
* @param o 被观察对象,也就是主题对象--在这里是course需要强转
* @param arg 传参
*/
@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());
}
}
Question类
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;
}
}
public class Test {
public static void main(String[] args) {
Course softwareDesign = new Course("高级软件设计");
Teacher teacher = new Teacher("潘敏学");
softwareDesign.addObserver(teacher);
//业务逻辑代码
Question question = new Question();
question.setUserName("小马哥");
question.setQuestionContent("什么是观察者模式?");
softwareDesign.produceQuestion(softwareDesign,question);
}
}