概述
在观察者模式中,定义对象之间的 一对多依赖关系,每当一个对象状态发生改变时,其相关依赖对象都会得到通知并自动更新。
该模式主要有如下角色:
- 抽象目标Subject
- 具体目标ConcreteSubject
- 抽象观察者
- 具体观察者
示例
以手机app推送信息为例,app中推送的信息分为比赛信息,新闻信息等,每当出现一个新信息,它会被推送给订阅用户。此处新信息是被观察者,订阅用户是观察者。
首先定义一个新闻类,它不属于模式的任意一个角色、
public class News {
private String title;
private String content;
//省略get/set方法
}
抽象观察者:用户
public interface People {
void receiveNews(News news);
}
抽象目标:可以理解为app的各种推送信息的大致定义,它持有一个管理所有订阅用户的数组。
public interface Subject {
List<People> subPeople = new ArrayList<>();
default void addSubscriptionPeople(People people) {
subPeople.add(people);
}
default void remove(People people) {
subPeople.remove(people);
}
void sendNews();
}
具体目标——负责将新闻信息推送给订阅用户类NewsSubject
public class NewsSubject implements Subject {
@Override
public void sendNews() {
for(People people : subPeople) {
News news = new News();
news.setTitle("震惊!!!三亿中国人都看哭了,不转不是中国人");
news.setContent("呱");
people.receiveNews(news);
}
}
}
具体观察者——各种订阅用户类:路人A,路人B
public class PeopleA implements People {
@Override
public void receiveNews(News news) {
System.out.println("?呱呱呱");
}
}
public class PeopleB implements People {
@Override
public void receiveNews(News news) {
System.out.println("?咕咕咕");
}
}
测试一下:
public class Test {
public static void main(String[] args) {
Subject subject = new NewsSubject();
subject.addSubscriptionPeople(new PeopleA());
subject.addSubscriptionPeople(new PeopleB());
subject.sendNews();
}
}
总结
优点
(1)目标(推送信息)和观察者(订阅用户)之间是一个松耦合关系:目标只知道当前有哪些观察者(如本例中通过ArrayList管理订阅用户),并发送推送信息,但它不知道观察者后续会执行怎样的操作。
(2)符合开闭原则:若需要增加一个观察者(如增加一个路人C),只需写一个实现抽象观察者的类即可。
缺点
(1)在测试类中,需要知道所有的观察者,并执行增加/删除观察者操作。
(2)若一个被观察者对象有很多的直接和间接的观察者,则所有的观察者收到通知会花费很多时间。
(3)若被观察者之间有循环依赖,则可能会触发它们之间循环调用,导致系统崩溃。