观察者模式
定义: 多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象, 从而影响其他对象的行为
优点:
- 观察者和被观察者是抽象耦合的
- 设置了一套触发机制
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知是比较耗时的
- 观察者和被观察者如果存在循环依赖,会触发它们之间进行循环调用,可能导致系统崩溃
- 无法知道目标是如何发生变化的,仅仅只能了解到其发生了变化
使用场景:
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
应用实例: Spring 监听器、nacos 、MQ…
实现
假设我们有一邮箱服务 (MailServer 被观察者),在收到邮件后会发送推送信息给关注的平台 (如:网易邮箱大师、QQ邮箱助手等 观察者)
关系图如下:
代码实现:
观察者:
/**
* 抽象的观察者
*/
public abstract class AbstractObserver {
public abstract void update(String message);
}
/**
* 观察者实现
* 网易邮箱大师
*/
public class ObserverUser1 extends AbstractObserver{
private String userName;
private String message;
public ObserverUser1(String userName) {
this.userName = "网易邮箱大师用户:" + userName;
}
@Override
public void update(String message) {
this.message = message;
receiveMessage();
}
public void receiveMessage() {
System.out.println(userName + " 收到推送信息!" + message);
}
}
/**
* 观察者实现
* QQ邮箱助手
*/
public class ObserverUser2 extends AbstractObserver{
private String userName;
private String message;
public ObserverUser2(String userName) {
this.userName = "QQ邮箱助手用户:" + userName;
}
@Override
public void update(String message) {
this.message = message;
receiveMessage();
}
public void receiveMessage() {
System.out.println(userName + " 收到推送信息!" + message);
}
}
被观察者:
/**
* 抽象被观察者抽象类
*/
public abstract class Subject {
/**
* 注册到观察列表
*/
public abstract void registerObserver(AbstractObserver o);
/**
* 从观察列表移除
*/
public abstract void removeObserver(AbstractObserver o);
/**
* 通知所有观察者
*/
public abstract void notifyObserver();
}
/**
* 被观察者实现类
*/
public class MailServer extends Subject{
private List<AbstractObserver> list;
private String message;
public MailServer() {
list = new ArrayList<AbstractObserver>();
}
@Override
public void registerObserver(AbstractObserver o) {
list.add(o);
}
@Override
public void removeObserver(AbstractObserver o) {
if (!list.isEmpty()) {
list.remove(o);
}
}
@Override
public void notifyObserver() {
for (AbstractObserver o : list) {
o.update(message);
}
}
public void pushMessage(String s) {
this.message = s;
System.out.println("邮箱服务推送了消息:" + message);
// 通知索引观察者
notifyObserver();
}
}
测试类及运行结果:
public class Test {
public static void main(String[] args) {
MailServer mailServer = new MailServer();
// 构建观察者
ObserverUser1 zhangSan = new ObserverUser1("张三");
ObserverUser1 liSi = new ObserverUser1("李四");
ObserverUser2 wangWu = new ObserverUser2("王五");
ObserverUser2 zhaoLiu = new ObserverUser2("赵六");
// 观察者观察邮箱服务
mailServer.registerObserver(zhangSan);
mailServer.registerObserver(liSi);
mailServer.registerObserver(wangWu);
mailServer.registerObserver(zhaoLiu);
// 邮箱服务推送消息
mailServer.pushMessage("邮件提醒:如花给您发送了一封邮件");
// 不通知赵六
mailServer.removeObserver(zhaoLiu);
System.out.println("----------------赵六取消关注-----------------");
// 邮箱服务推送消息
mailServer.pushMessage("邮件提醒:品如给您发送了一封邮件");
}
}
---------运行结果--------
邮箱服务推送了消息:邮件提醒:如花给您发送了一封邮件
网易邮箱大师用户:张三 收到推送信息!邮件提醒:如花给您发送了一封邮件
网易邮箱大师用户:李四 收到推送信息!邮件提醒:如花给您发送了一封邮件
QQ邮箱助手用户:王五 收到推送信息!邮件提醒:如花给您发送了一封邮件
QQ邮箱助手用户:赵六 收到推送信息!邮件提醒:如花给您发送了一封邮件
----------------赵六取消关注-----------------
邮箱服务推送了消息:邮件提醒:品如给您发送了一封邮件
网易邮箱大师用户:张三 收到推送信息!邮件提醒:品如给您发送了一封邮件
网易邮箱大师用户:李四 收到推送信息!邮件提醒:品如给您发送了一封邮件
QQ邮箱助手用户:王五 收到推送信息!邮件提醒:品如给您发送了一封邮件
Process finished with exit code 0