1 模式简介
观察者模式的介绍:
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新。
发布者(被观察者) + 订阅者(观察者) = 观察者模式
观察者模式的优点:
1) 观察者和被观察者是抽象耦合的;
2) 观察者模式建立了一套触发机制(触发联动)。
观察者模式的缺点:
1) 如果一个被观察者有很多直接或简介的观察者的话,将所有的观察者都通知到会花费很多时间;
2) 如果在观察者和被观察者之间有循环依赖的话,被观察者会触发它们之间的的循环调用,可能会导致系统崩溃(因此,在观察者模式中应该避免观察者和被观察者之间的循环调用)。
观察者模式的适用场景:
1) 当需要完成“触发联动”的功能时,即当一个对象的状态发生变化时,会触发与之相关联的多个对象状态的改变;
2) 当观察者对象不需要知道主题对象(被观察者)的实现细节时。
观察者模式的UML图:
2 案例
在这个案例中,我们模拟报社的职能:
1) 报社的业务就是出版报纸;
2) 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,就会一直收到新报纸;
3) 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来;
4) 只要报社还在运营,就会一直有人向他们订阅或取消订阅报纸。
2.1 手写观察者模式
手写的观察者模式的代码如下:
被观察者的抽象父类Subject代码如下:
public abstract class Subject {
protected String name;
protected Object thing;
abstract void addObserver(Observer observer);
abstract void removeObserver(Observer observer);
abstract void notifyObservers();
public void setThing(Object thing) {
this.thing = thing;
System.out.println(this.name + "发布了一条消息:" + thing.toString());
notifyObservers();
}
}
被观察者的具体类:报社类NewsOffice中的代码:
import java.util.ArrayList;
import java.util.List;
public class NewsOffice extends Subject {
private List<Observer> observers;
public NewsOffice() {
super.name = "报社";
this.observers = new ArrayList<Observer>();
}
@Override
public void addObserver(Observer observer) {
this.observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
int index = this.observers.indexOf(observer);
if (index >= 0) {
this.observers.remove(observer);
}
}
@Override
void notifyObservers() {
if (this.observers.size() > 0) {
for (Observer observer : this.observers) {
observer.update(super.thing);
observer.display();
}
}
}
}
观察者的抽象父类Observer中的代码:
public abstract class Observer {
protected String name;
protected Object thing;
public void update(Object thing) {
this.thing = thing;
System.out.println(this.name + "收到了消息:" + thing.toString());
}
public abstract void display();
}
具体的观察者Person1中的代码:
public class Person1 extends Observer {
public Person1() {
super.name = "Person1";
}
@Override
public void display() {
System.out.println(super.name + "一边听歌一边看报纸");
}
}
具体的观察者还有Person2和Company1,这里以Person1为例,有需要的朋友可以通过博客最后的GitHub地址去GitHub上下载。
测试类Test中的代码:
public class Test {
public static void main(String[] args) {
// 创建主题(被观察者)
Subject office = new NewsOffice();
// 创建观察者
Observer person1 = new Person1();
Observer person2 = new Person2();
Observer company1 = new Compony1();
// 为观察者注册主题
office.addObserver(person1);
office.addObserver(person2);
office.addObserver(company1);
// 主题发送消息
office.setThing("第一条新闻");
System.out.println();
office.setThing("哈哈哈哈哈哈哈哈哈哈");
}
}
运行结果如下图所示:
2.2 JAVA内置观察者模式
JAVA内置的观察者模式的代码如下:
被观察者报社类NewsOffice(继承了JAVA内置的被观察者Observable类)的代码如下:
public class NewsOffice extends Observable {
public void setNews(String news) {
System.out.println("报社发布了新闻:" + news);
super.setChanged();
super.notifyObservers(news);
}
}
自定义的观察者CustomObserver(实现了JAVA内置的观察者接口Observer和自定义的展示接口IDisplay)的代码如下:
// 自定义的展示接口IDisplay中的代码:
public interface IDisplay {
void display();
}
// 自定义的观察者CustomObserver中的代码:
public abstract class CustomObserver implements Observer, IDisplay {
protected String name;
@Override
public void update(Observable subject, Object thing) {
System.out.println(this.name + "收到了消息:" + thing.toString());
}
}
具体观察者Person1中的代码:
public class Person1 extends CustomObserver {
public Person1() {
super.name = "Person1";
}
@Override
public void display() {
System.out.println(super.name + "一边听歌一边看报纸");
}
}
Person2和Company1中的代码同样在GitHub中。
测试类Test中的代码:
public class Test {
public static void main(String[] args) {
// 创建主题(被观察者)
NewsOffice office = new NewsOffice();
// 创建三个观察者
CustomObserver person1 = new Person1();
CustomObserver person2 = new Person2();
CustomObserver company1 = new Company1();
// 为观察者注册主题
office.addObserver(person1);
office.addObserver(person2);
office.addObserver(company1);
// 被观察者发布消息
office.setNews("哈哈哈哈哈哈");
System.out.println();
office.setNews("这不是一条垃圾新闻");
}
}
运行结果如下图所示:
最后贴出观察者模式的GitHub代码地址:【GitHub - Observer】。