mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-31 19:13:42 +00:00
Update 设计模式 - 目录.md
补充 JDK 集合中的设计模式示例及责任链模式的处理注意事项,更新常见场景表格链接,并补充三种工厂、策略与状态、代理与装饰等易混淆模式的对比。
This commit is contained in:
+11
-5
@@ -12,7 +12,9 @@
|
||||
- 结构型关注类和对象如何组合成更大的结构,常用的有[适配器](设计模式%20-%20适配器.md)、[装饰](设计模式%20-%20装饰.md)和[代理](设计模式%20-%20代理.md);
|
||||
- 行为型关注对象之间如何分配职责和通信,常用的有[策略](设计模式%20-%20策略.md)、[观察者](设计模式%20-%20观察者.md)、[责任链](设计模式%20-%20责任链.md)和[模板方法](设计模式%20-%20模板方法.md)。
|
||||
|
||||
JDK 中,Runtime.getRuntime() 是单例,Calendar.getInstance() 是静态工厂方法,BufferedInputStream 包装其它输入流以增加缓冲,属于装饰器。Arrays.asList() 把数组适配为 List,属于适配器;java.lang.reflect.Proxy 在运行时生成代理对象。
|
||||
JDK 中,Runtime.getRuntime() 是单例,Calendar.getInstance() 是静态工厂方法,BufferedInputStream 包装其它输入流以增加缓冲,属于装饰。Arrays.asList() 把数组适配为 List,属于适配器;java.lang.reflect.Proxy 在运行时生成代理对象。
|
||||
|
||||
集合框架中,List.sort() 传入的 Comparator 是策略,换一个 Comparator 就换一种排序规则;继承 AbstractList 只需实现 get() 和 size(),indexOf()、contains() 等方法由父类基于这两个方法实现,属于模板方法;Collection#iterator() 由各实现类决定返回哪种迭代器,属于工厂方法。
|
||||
|
||||
Spring 中的用法见 [Spring 中的设计模式](Spring.md#七spring-中的设计模式)。
|
||||
|
||||
@@ -27,8 +29,8 @@ Spring 中的用法见 [Spring 中的设计模式](Spring.md#七spring-中的设
|
||||
| 下单前的校验 | 校验项不断增加:参数、限购、黑名单、库存 | [责任链](设计模式%20-%20责任链.md) |
|
||||
| 计算运费、选择支付渠道 | 同一件事有多种算法,按类型选择其中一种 | [策略](设计模式%20-%20策略.md)加[简单工厂](设计模式%20-%20简单工厂.md) |
|
||||
| 接收多家物流公司的回调 | 步骤固定(验签、幂等、处理、应答),只有处理的部分不同 | [模板方法](设计模式%20-%20模板方法.md) |
|
||||
| 支付成功后加积分、发短信 | 接收方不断增加,发布方不想知道有哪些接收方 | [观察者](设计模式%20-%20观察者.md) |
|
||||
| 事务、分布式锁、日志 | 与业务无关、很多方法都要加的逻辑 | [代理](设计模式%20-%20代理.md),即 Spring AOP |
|
||||
| 支付成功后加积分、发短信 | 接收方不断增加,发布方不想知道有哪些接收方 | [观察者](设计模式%20-%20观察者.md),即 [Spring 的事件](Spring.md#七spring-中的设计模式) |
|
||||
| 事务、分布式锁、日志 | 与业务无关、很多方法都要加的逻辑 | [代理](设计模式%20-%20代理.md),即 [Spring AOP](Spring.md#动态代理) |
|
||||
|
||||
以下单前的校验为例,每个校验项是一个处理者,按顺序执行,任何一个不通过就抛出异常,后面的不再执行:
|
||||
|
||||
@@ -68,11 +70,15 @@ public class OrderService {
|
||||
|
||||
再加上库存校验(@Order(3)),购买 3 件时依次执行参数校验、限购校验,抛出“每人限购 2 件”,库存校验不再执行(Spring Boot 3.3 实测,见[附录 A1](#a1-下单校验的责任链))。新增黑名单校验只需要再写一个带 @Component 的实现类,OrderService 不用修改。
|
||||
|
||||
需要注意的是,链上的处理者最好只做校验这类不修改数据的事。如果某个处理者已经扣了优惠券,后面的处理者再失败,前面的修改不会自动撤销,需要把整条链放在一个事务中,或者由处理者提供补偿操作。链条变长以后,请求在哪一环被拦下也要靠日志才能查清。
|
||||
|
||||
几个容易混淆的模式:
|
||||
|
||||
- 策略和工厂常一起出现:工厂决定取得哪一个对象,策略决定执行哪一种算法,见[与简单工厂和 Spring 容器结合](设计模式%20-%20策略.md#2-与简单工厂和-spring-容器结合);
|
||||
- 工厂方法一次创建一个对象,由子类决定创建哪一种;抽象工厂创建一组必须一起使用的相关对象,见[抽象工厂](设计模式%20-%20抽象工厂.md);
|
||||
- 责任链中的请求依次经过多个处理者,策略只选择其中一个算法执行。
|
||||
- 三种工厂:[简单工厂](设计模式%20-%20简单工厂.md)由一个类按参数创建各种产品,新增产品要修改它;[工厂方法](设计模式%20-%20工厂方法.md)由子类决定创建哪一种,新增产品只需新增子类;[抽象工厂](设计模式%20-%20抽象工厂.md)创建一组必须一起使用的相关对象;
|
||||
- 责任链中的请求依次经过多个处理者,策略只选择其中一个算法执行;
|
||||
- 策略和状态的类图相似,策略通常由客户端选择并替换,状态随运行中的状态转移而切换(转移逻辑写在状态对象或 Context 中),见[与状态模式的比较](设计模式%20-%20策略.md#与状态模式的比较);
|
||||
- 代理和装饰的结构相同,都实现被包装对象的接口并持有它的引用,代理用来控制访问,装饰用来叠加功能,见[代理](设计模式%20-%20代理.md)。
|
||||
|
||||
需要注意的是,模式不是用得越多越好。只有两三个分支、短期内不会再增加的 if-else 不需要改成策略,引入模式的理由应该是已经出现或可以预见的变化。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user