大纲
什么是观察者设计模式?
观察者设计模式是一种对象行为模式,有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式、从属者模式、发布订阅模式)。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式的组成角色
1、抽象主题(Subject):
它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供增加和删除观察者对象的接口。
2、具体主题(Concrete Subject):
将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3、抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4、具体观察者(Concrete Observer):
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调
观察者模式类图如下图所示:
代码实现
//抽象主题,即抽象被观察对象
public interface Subject {
void add(Observer observer);
void remove(Observer observer);
void notifyObserver();
}
//具体被观察对象
class ConcreteSubject implements Subject {
private List<Observer> listeners = new ArrayList<>();
@Override
public void add(Observer observer) {
this.listeners.add(observer);
}
@Override
public void remove(Observer observer) {
this.listeners.remove(observer);
}
@Override
public void notifyObserver() {
for (Observer listener : listeners) {
listener.response();
}
}
}
//抽象观察者
interface Observer {
void response();
}
//具体观察者
class ConcreteObserver1 implements Observer{
@Override
public void response() {
System.out.println("观察者1");
}
}
//具体观察者
class ConcreteObserver2 implements Observer{
@Override
public void response() {
System.out.println("观察者2");
}
}
class ClientTest{
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
ConcreteObserver1 observer1 = new ConcreteObserver1();
ConcreteObserver2 observer2 = new ConcreteObserver2();
subject.add(observer1);//观察者1
subject.add(observer2);//观察者2
subject.notifyObserver();//被观察者发生变化,主动通知观察者
}
}
至此,基本的观察者设计模式已经实现了,但是,我们分析一下上面的代码,每次被观察对象发生改变,都会触发所有的观察者响应,假如有上百甚至上千个观察者,是否每次被观察对象发生变化,所有的观察者都要进行响应呢?
Subject subject = new ConcreteSubject();
ConcreteObserver1 observer1 = new ConcreteObserver1();
ConcreteObserver9999 observer9999 = new ConcreteObserver2();
//此处省略上万个观察者...
subject.add(observer1);
//...
subject.add(observer9999);
//被观察者对象发生变化啦
subject.notifyObserver();
//响应1
//...
//响应9999
进阶学习
面对上述情况,我们可以对代码进行改造,主题发生变化则发布特定的事件,监听该事件的观察者做出响应。
//抽象事件
public abstract class CustomEvent {
}
//具体事件
public class LoginCustomEvent extends CustomEvent {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//抽象主题
public interface Subject {
void add(Observer observer);
void remove(Observer observer);
//事件发生变化,只通知监听该事件的观察者
void notifyObserver(CustomEvent event);
}
//具体主题
class ConcreteSubject implements Subject {
private List<Observer> listeners = new ArrayList<>();
@Override
public void add(Observer observer) {
this.listeners.add(observer);
}
@Override
public void remove(Observer observer) {
this.listeners.remove(observer);
}
@Override
public void notifyObserver(CustomEvent event) {
for (Observer listener : listeners) {
Type[] types = listener.getClass().getGenericInterfaces();
for (Type type : types) {
String typeName = type.getTypeName();
ParameterizedType parameterizedType = (ParameterizedType) type;
Type argument = parameterizedType.getActualTypeArguments()[0];
//找出具体观察者监听的事件名称
String argumentTypeName = argument.getTypeName();
//事件名称
String eventName = event.getClass().getName();
//如果名称相等,则表明该观察者监听该事件,实际开发可不能这么简单的判断哟
if (argumentTypeName.equals(eventName)) {
listener.response(event);
}
}
}
}
}
interface Observer<Event extends CustomEvent> {
void response(Event customEvent);
}
class ConcreteObserver1 implements Observer<LoginCustomEvent> {
@Override
public void response(LoginCustomEvent customEvent) {
System.out.println("触发登录事件");
System.out.println(customEvent.getName());
}
}
class ClientTest {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
ConcreteObserver1 observer1 = new ConcreteObserver1();
LoginCustomEvent event = new LoginCustomEvent();
event.setName("loginEvent");
subject.add(observer1);
subject.notifyObserver(event);
}
}
至此,我们实现了主题发生变化通过发布不同的事件,通知监听该事件的观察者即可,避免了无关的观察者也作出响应,提高代码的灵活度。
优缺点
观察者模式的主要的作用就是对对象解耦,将观察者和被观察者完全隔离。
1、观察者模式的优点
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体,符合依赖倒置原则。
2、观察者模式的缺点
在应用观察者模式时需要考虑一下开发小路问题,程序中包括一个被观察者和多个被观察者,开发和调试比较复杂,而且Java中的消息的通知默认是顺序执行的,一个观察者的卡顿会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。
导致系统变得复杂,当然,引入了设计模式必然会提高系统的复杂性。
应用场景
1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2、当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要被改变。
3、当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,不希望这些对象是紧密耦合的。
这里举几个实际应用的场景:
用户注册成功后发送邮件给用户;
支付场景:用户购买商品时,用户支付成功之后三方会回调自身,在这个时候系统可能会有很多需要执行的逻辑 (如:更新订单状态,发送邮件通知,赠送礼品…)
文章审核:发文章通常需要我们的领导进行审核,审核通过需要怎么处理,不通过又怎么处理,都可以使用观察者设计模模式处理。
以上仅为个人学习总结,如有错误欢迎指出。