温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何避免观察者模式坑

发布时间:2026-07-18 15:28:45 来源:亿速云 阅读:90 作者:小樊 栏目:编程语言

观察者模式(Observer Pattern)用起来很爽,但坑也不少。下面从常见坑点 → 原因 → 规避方式系统讲一遍,基本能覆盖 90% 的实际问题。


一、最常见的 8 个坑

1️⃣ 内存泄漏(最经典)

现象

  • 观察者注销失败
  • 对象已经不用了,却还被通知
  • 内存一直涨

原因

  • 被观察者持有观察者的强引用
  • 忘记 unsubscribe / removeObserver

规避

// 典型错误
subject.addObserver(this);
// 页面销毁时忘了 remove

✅ 正确做法:

  • 生命周期绑定
  • 使用 WeakReference
  • 框架自动管理(RxJava、LiveData、Flow)
@Override
protected void onDestroy() {
    subject.removeObserver(this);
}

2️⃣ 观察者顺序不可控

现象

  • 通知顺序和注册顺序不一致
  • 不同环境表现不同

原因

  • 使用 HashSet / HashMap 存观察者

规避

  • 明确顺序需求
  • 使用 List / CopyOnWriteArrayList
List<Observer> observers = new CopyOnWriteArrayList<>();

3️⃣ 观察者里做耗时操作

现象

  • 通知卡顿
  • UI 卡死
  • 被观察者线程被拖慢

原因

  • 观察者直接做 IO / 计算

规避

  • 观察者只做“响应”
  • 耗时逻辑异步处理
observer.onEvent(e -> {
    asyncRun(() -> handle(e));
});

4️⃣ 通知过程中修改观察者列表

现象

  • ConcurrentModificationException
  • 漏通知 / 重复通知

原因

  • onNext() 里 add / remove observer

规避

  • 遍历副本
  • 使用并发容器
for (Observer o : new ArrayList<>(observers)) {
    o.update();
}

5️⃣ 观察者抛异常,影响其他人

现象

  • 一个观察者崩了
  • 后面观察者全收不到通知

规避

  • 统一 catch
  • 或设计容错策略
try {
    observer.update();
} catch (Exception e) {
    log.error("observer error", e);
}

6️⃣ 观察者和被观察者强耦合

现象

  • 观察者依赖具体实现
  • 无法复用、无法单测

原因

  • 直接依赖具体类

规避

  • 面向接口
  • 事件对象解耦
interface Observer {
    void onEvent(Event e);
}

7️⃣ 事件爆炸(通知太频繁)

现象

  • 高频更新(如滚动、动画)
  • 性能急剧下降

规避

  • 合并事件(throttle / debounce)
  • 控制通知粒度

8️⃣ 滥用观察者模式

现象

  • 所有模块都用观察者
  • 逻辑跳转混乱,调试困难

规避

  • 不是所有“通知”都该用观察者
  • 优先用:
    • 直接调用
    • 回调
    • 状态管理(ViewModel / Store)

二、设计层面如何提前避坑

✅ 1. 明确角色边界

  • Subject:只负责通知
  • Observer:只负责响应
  • 不做业务编排

✅ 2. 区分「事件」和「状态」

  • 事件:发生一次
  • 状态:一直存在
场景 建议
UI 状态 LiveData / StateFlow
一次性事件 EventBus / 回调
复杂业务 状态机 / Redux

✅ 3. 使用成熟实现,别自己造轮子

场景 推荐
Android LiveData / StateFlow
Java RxJava
JS RxJS
后端 Guava EventBus

三、一个“安全版”观察者模板

class SafeSubject {
    private final List<Observer> observers = new CopyOnWriteArrayList<>();

    void add(Observer o) {
        observers.add(o);
    }

    void remove(Observer o) {
        observers.remove(o);
    }

    void notify(Event e) {
        for (Observer o : observers) {
            try {
                o.onEvent(e);
            } catch (Exception ex) {
                log.error(ex);
            }
        }
    }
}

四、什么时候不该用观察者

❌ 调用链很短
❌ 逻辑必须同步
❌ 强顺序依赖
❌ 调用者和被调用者天然强关联


五、一句话总结

观察者模式最大的坑不是模式本身,而是“通知谁、什么时候通知、什么时候取消、谁负责生命周期”。

如果你愿意,我可以:

  • 帮你 review 一段观察者代码
  • 或对比 观察者 vs 发布订阅 vs 回调
  • 或结合 Android / 后端 / 前端 给你具体建议
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI