- Published on
设计模式
- Authors

- Name
- Li WenKang
- https://x.com/liwenkang_space
单例模式
确保一个类只有一个实例,并提供全局访问点。保证了一个类只有一个实例。
解决了什么问题?
保证全局唯一,避免数据状态混乱,节省资源。比如 modal 弹窗(只需要一个,最多替换里面的内容),比如文档编辑器示例(一个页面中只需要一个,允许操作这个示例),比如 Redux(只需要一个管理全局数据)
最佳实践:
- ES6 导出的对象也是唯一的,无需手动实现单例
- 实现的时候需要注意隐藏构造函数(防止随便 new),通过统一的入口比如 getInstance 处理
- 多线程环境下可能破坏唯一性(如两个线程同时创建实例),需补充“双检锁”等解决方案,浏览器由于是单线程的,不用考虑此问题
发布订阅模式
通过事件调度中心(Event Bus)实现发布者和订阅者的解耦
解决了什么问题?
可以通过 event 实例,跨组件传递数据(在需要接收数据的地方,监听事件。在需要发送数据的地方,触发事件),无需耦合在一起,需要设计消息确认机制(避免消息丢失)
最佳实践:
- 需首先保证 event 实例全局唯一
- 不可滥用事件传递,过多使用可能导致数据流混乱,难以排查问题
- 一个简单的事件调度中心(Event Bus)实现:搞一个 WeakMap,当有人注册事件监听的时候,就存入 WeakMap 中,当有人触发事件,则在 WeakMap 里面找到对应事件的回调函数并执行,如果要注销事件监听,就把 Map 中对应事件的回调函数删除
- 注意取消订阅,避免内存泄露
工厂模式
通过将对象的创建和使用分离,将对象的创建过程封装在工厂类中,使用者只需传参,无需关心对象构建细节。
解决了什么问题?
适用于需要批量创建多个类似的复杂对象(比如按钮,表单)
最佳实践
如果所需对象简单且仅需使用一次,则没必要必须使用工厂模式
策略模式
将算法封装成可互换的"技能包",运行时动态切换。
解决了什么问题?
在不改变对象本身的情况下,通过修改内部的逻辑,实现对不同场景的适配。
最佳实践:
常用来替换复杂的 if/else 嵌套场景,让策略独立于主逻辑(比如支付方式的选择)
责任链模式
将多个处理器串联成链,请求沿链传递,直到有处理器处理
解决了什么问题?
如果一个请求与多个请求处理者混合在一起,则会出现混乱。可以将所有请求的处理者通过前一对象记住下一对象的方式形成一条链,然后将请求沿着链传递,直到有一个对象处理它为止。比如在 ai 对话的解析场景中,接口返回的内容中,包含了 messageType 字段,用来做场景区分,前端拆分出多个对应的 handler(责任独立),让接口返回的内容一层层沿着 handler 传递,直到出现匹配的 handler,进行处理。
最佳实践
- 需要注意实际业务中,责任链的顺序是否会影响业务逻辑,最好设计成无影响的,有利于后期拓展和维护
- 如果出现链中无处理者时,需要设计兜底的默认逻辑