一、简介
观察者模式是一种使用率很高的模式。这个模式的一个重要作用就是解耦,将被观察者和观察者解耦。在很多地方,都会将观察者模式称为发布-订阅模式,或者订阅者模式。实际上,两者是不完全相同的,有联系也有区别。
二、观察者模式定义
观察者模式,定义了一种一对多的依赖关系,使得当一个对象发生状态变化时,则观察它的对象也都得到通知并作出反应。
三、UML类图
- 抽象主题(Subject):它把所有观察者对象的引用保存到一个集合中,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以注册和移除观察者。
- 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
- 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体观察者(ConcreteObserver):实现抽象观察者提供的更新接口,以便本身的状态能够及时更新。
四、观察者模式的实现例子
1、创建一个抽象观察者
public interface Observer {//抽象观察者
public void update(String message);//更新方法
}
2、创建具体观察者(以开学为例)
public class Student implements Observer {
private String name;
public Student (String name) {
this.name = name;
}
@Override
public void termBegins(String message) {
System.out.println(message + "," + name+"背上书包去学校");
}
}
public class Teacher implements Observer {
private String name;
public Teacher (String name) {
this.name = name;
}
@Override
public void termBegins(String message) {
System.out.println(message + "," + name+"准备布置新学期学习任务");
}
}
3、创建抽象主题
public interface Observable {
void add(Observer observer);
void remove(Observer observer);
void notify(String message);
}
4、创建具体主题
public class School implements Observable{
private List<Observer> personList = new ArrayList<Observer>();
@Override
public void add(Observer observer) {
personList.add(observer);
}
@Override
public void remove(Observer observer) {
personList.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : personList) {
observer.termBegins(message);
}
}
}
5、客户端测试
public void test(){
Observable school = new School();
Observer stu1=new Student("小明");
Observer teacher1=new Teacher("王老师");
school.add(stu1);
school.add(teacher1);
school.notify("开学了!");
}
五、发布-订阅模式
联系
发布-订阅模式是观察者模式的一种变体。发布-订阅只是把一部分功能抽象成一个独立的“中间件”进行转发控制。
区别
1、观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方来实现调度的,发布者和订阅者之间互不感知。
观察者模式比较好理解,发布订阅模式举个栗子,就像报社, 邮局和个人的关系,报纸的订阅和分发是由邮局来完成的。报社只负责将报纸发送给邮局。
2、观察者模式是【一对多】的关系。一触发通知,所有观察者都收到消息。
发布-订阅模式是【多对一】或者【多对多】的关系。
发布-订阅模式适合更复杂的场景,比如只想通知部分订阅者,比如多个发布者发布消息时,通知时机的选择(都发布完再通知还是每发布一个通知一次)。而这些控制的逻辑就是在“中间件”完成的。
六、发布-订阅模式例子
var publisher = {
publish(pubsub) {
pubsub.publish()
}
}
var pubsub = {
subscribes: [],
publish() {
this.subscribes.forEach(subscribe =>{
subscribe.update();
})
},
subscribe(sub) {
this.subscribes.push(sub)
}
}
var subscribe = {
update() {
console.log('update')
},
subscribe(pubsub) {
pubsub.subscribe(this);
}
}
subscribe.subscribe(pubsub)
publisher.publish(pubsub)
感谢-> https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/25
看代码就很容易理解了。转一下java实现也不难,这里就偷个懒了~