基本介绍
观察者模式(Observer Pattern)又被称为发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式,属于行为型模式的一种。
定义了一种一对多的模式,多个观察者监视一个主题,当主题状态发生变化时,会通知所有观察者。观察者之间没有互相联系,可以增加、删除观察者,易于管理和扩展。
模式结构
Subject(抽象主题):和观察者是一对多的关系,即一个主题可以绑定多个观察者
ConcreteSubject(具体主题):实现抽象主题的方法,当主题内部发生变化时,通知所有绑定的观察者
Observer(抽象观察者):定义了更新的方法,当主题有变化时,通过此方法更新自己
ConcreteObserver(具体观察者):实现抽象观察者,实现更新方法
举例说明
以用户和频道为例,当频道有新的消息时,会将通知发送给所有订阅了该频道的用户
1、抽象观察者,定义了一个更新的方法
public interface Observer {
void update(String message);
}
2、具体观察者:用户,定义一个名称属性,实现抽象观察者的方法
public class UserObserver implements Observer {
private String name;
public UserObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "收到通知:" + message);
}
}
3、抽象主题,有添加、删除、通知功能
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notify(String message);
}
4、具体主题:新闻频道,定义一个 List 存储观察者,通知时循环遍历集合进行通知
public class NewsSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
5、测试类
public class Client {
@Test
public void test() {
Subject newsSubject = new NewsSubject();
Observer user1 = new UserObserver("小龙");
Observer user2 = new UserObserver("小凤");
newsSubject.attach(user1);
newsSubject.attach(user2);
newsSubject.notify("新闻频道发布了一条紧急新闻");
}
}
6、运行结果
小龙收到通知:新闻频道发布了一条紧急新闻
小凤收到通知:新闻频道发布了一条紧急新闻
7、如果我们需要添加其它频道也非常的方便,只需要添加一个具体主题(比如体育频道),其它业务代码无需改动,测试类中将用户注册进去即可。
模式分析
优点
- 耦合性低,让耦合的双方都依赖于抽象,当发生变化时,双方互不干扰
- 扩展性高,添加具体主题或是添加具体观察者,都无需修改其他代码
缺点
- 如果一个主题有很多直接或间接的观察者,则通知的过程会花费很多时间
- 如果主题和观察者之间有循环依赖,可能会造成程序死循环导致系统崩溃
适用场景
- 观察者模式在软件开发中应用非常广泛,比如电商系统可以在执行发送操作后给用户多个发送商品打折信息,游戏中队友牺牲将给所有成员提示等等,凡是涉及到一对一或者一对多的对象交互场景都可以使用观察者模式。