《Head First 设计模式》 学习笔记,码云同步更新中
如有错误或不足之处,请一定指出,谢谢~
目录
查看其它设计模式笔记,点这里→设计模式笔记汇总
观察者模式
- 定义:
- 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新
- 结构:
- Subject:主题接口
- ConcreteSubject:具体主题
- Observer:观察者接口
- ConcreteObserver:具体观察者
- 优点:
- 具体主题和具体观察者之间为松耦合关系
- 符合“开闭原则”
- 缺点:
- 没有相应的机制使观察者知道主题是如何发生变化的
- 如果观察者之间存在循环调用,会导致系统崩溃,需要特别注意
- 适用范围:
- 一个对象的改变需要触发其他多个对象的改变,但不知道具体有多少需要改变的对象,降低对象间的耦合
- 一个对象需要通知很多其他对象,但不需要知道他们是谁
- 与发布-订阅模式的区别
- 发布-订阅模式中,发布者不直接和订阅者通信,他们甚至不知道对方的存在。他们通过第三方信息中介进行通信
- 观察者模式大多是同步的,而发布-订阅模式大多是异步的(消息队列)
- 其他:
- 在另一个例子中:气象台(主题)发布实时数据(间隔很短,假设1秒一次),
布告板(观察者)显示气温(有可能实时,也有可能每天一次,或者统计月平均数据)。
这种情况下观察者需要将接收到的数据缓存下来,然后在各自设定的时间对外展示。 - 在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了Java语言对观察者模式的支持。
- 在另一个例子中:气象台(主题)发布实时数据(间隔很短,假设1秒一次),
- 案例:
- 线上商城客户下单付款后,需要执行一系列业务逻辑,随时有可能增加或删去
- 发送短信
- 累计积分
- 购物节活动赠送小礼品
- 原有实现:在付款成功后的方法中增加相关代码,等到不需要时再删除代码。
- 问题:反复增删改付款核心逻辑,易出错,难维护。
- 观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新
- 创建观察者(通知)接口、被观察者(主题)接口
- 分别实现这两个接口——订单付款主题,返现观察者,发送信息观察者等等...
- 创建订单付款后处理器,可交由Spring管理,通过配置文件配置观察者向主题进行注册
- 在原订单付款后方法中,掉用处理器方法,让主题发出通知,各观察者接收通知执行各自逻辑
- 线上商城客户下单付款后,需要执行一系列业务逻辑,随时有可能增加或删去
- 代码:
/**
* 主题
*/
public interface Subject<T> {
/**
* 观察者注册
* @param o
*/
void registerObserver(Observer o);
/**
* 观察者退出
* @param o
*/
void removeObserver(Observer o);
/**
* 发出通知
* @param t
*/
void notifyObservers(T t);
}
/**
* 订单支付 主题
**/
public class OrderPaidSubject implements Subject<Order> {
/**
* 观察者名单
*/
private ArrayList<Observer> observerList;
public OrderPaidSubject() {
observerList = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observerList.add(o);
}
@Override
public void removeObserver(Observer o) {
observerList.remove(o);
}
/**
* 遍历观察者名单发送通知
* @param order
*/
@Override
public void notifyObservers(Order order) {
observerList.forEach(observer -> observer.update(order));
}
}
/**
* 观察者
*/
public interface Observer<T> {
/**
* 接收通知
*/
void update(T t);
}
/**
* 返现观察者
**/
public class CashBackOB implements Observer<Order> {
@Override
public void update(Order order) {
System.out.println("返现5元,订单编号:" + order.getOrderNo());
}
}
/**
* 发送短信观察者
**/
public class SendMsgOB implements Observer<Order> {
@Override
public void update(Order order) {
System.out.println("发送短信,订单编号:" + order.getOrderNo());
}
}
/**
* 订单
**/
@Data
public class Order {
private Integer orderId;
private String orderNo;
}
/**
* 订单支付后处理
**/
public class OrderPaidHandler {
private OrderPaidSubject orderPaidSubject;
public OrderPaidHandler() {
orderPaidSubject = new OrderPaidSubject();
// 可改造为 通过配置文件 注册
orderPaidSubject.registerObserver(new CashBackOB());
orderPaidSubject.registerObserver(new SendMsgOB());
}
public void orderIsPaid(Order order) {
orderPaidSubject.notifyObservers(order);
}
}
/**
* 测试类
**/
public class Test {
public static void main(String[] args) {
OrderPaidHandler orderPaidHandler = new OrderPaidHandler();
Order order = new Order();
order.setOrderId(1);
order.setOrderNo("01012254");
orderPaidHandler.orderIsPaid(order);
}
}
结果:
返现5元,订单编号:01012254
发送短信,订单编号:01012254
网友评论