软考复习:策略、工厂和适配器不要混用

设计模式名称记得很多,遇到题目仍可能选错。

edyang · 2013-02-25

设计模式名称记得很多,遇到题目仍可能选错。有效的判断入口是“变化发生在哪里”,而不是看到接口就套策略模式。

本文使用经典算法与关系数据库的纸面例题。复习时把概念放进一个可手算的小问题:先声明假设,再列状态变化,最后检查反例。题目中的边界条件往往比公式本身更容易失分。

1. 从现象推到机制

策略封装可以替换的行为,工厂集中对象创建,适配器转换不兼容接口。一套支付演示可以同时包含三者:选择计费算法、创建通道对象、把通道字段转换为内部模型。它们解决的变化维度不同。

软考复习:策略、工厂和适配器不要混用的处理、反馈与观察关系

图中的四个节点分别表示变化识别、抽象边界、替换实现、调用验证。顺着实线检查输入如何变成输出,再沿虚线核对反馈条件。图示表达的是本文讨论的关系,不是实测曲线或现场截图。

2. 最小实现与输入条件

先写一个只有两种计费方式的例子,调用方只依赖统一接口。对象从哪里来和算法怎样执行分别讨论,不急着加反射与配置中心。

1
2
3
4
5
6
7
8
9
interface FeePolicy { long fee(long amount); }
class FixedFee implements FeePolicy {
    public long fee(long amount) { return 20L; }
}
class Checkout {
    long total(long amount, FeePolicy p) {
        return amount + p.fee(amount);
    }
}

例题中的规模和耗时都是教学输入。先手算一遍,再用短程序核对;记录推导过程,避免只背住选项或最终数字。实际系统的性能不能直接从纸面复杂度推出。

3. 用对照区分原因

下表列出需要主动改变的条件。预期行为来自机制分析,复现时还需记录运行环境和原始输出,不能将预期当作已经测得的结果。

改变的条件 需要验证的行为
新增一种计算方式 调用流程不必增加计算分支
第三方参数名称不同 需要接口转换而非仅换算法
创建过程依赖配置 集中创建可减少调用方耦合

对照 1:新增一种计算方式

调用流程不必增加计算分支。观察时记录变化是否集中到新策略。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 2:第三方参数名称不同

需要接口转换而非仅换算法。观察时记录输入输出语义是否一致。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 3:创建过程依赖配置

集中创建可减少调用方耦合。观察时记录构造依赖有没有泄漏出去。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

4. 适用条件与取舍

抽象会增加理解成本。只有一个稳定实现时,先保持清晰的函数边界也合理;模式应降低已存在的变化成本,而不是预先堆积类层次。

一次正常运行只覆盖了这组输入。继续扩展前,应把上面的异常对照保留下来,尤其关注“创建过程依赖配置”这一分支。后续方案若改变了图中任意一处依赖,原来的判断就要重新验证,不能仅凭界面相似或返回值相同沿用结论。

同月延伸

参考资料

  1. MIT 算法课程资料
  2. Java SE 7 API 文档