拿到一套毛坯房,小白业主的第一反应往往是冲进建材市场,把最贵的瓷砖、进口的智能马桶一车车拉回家。资深设计师却会先拿出卷尺——量户型、问需求、算预算,然后才动笔出图。装修的成败从来不取决于“用了多少昂贵材料”,而取决于“每一处改动是否匹配真实的生活”。 设计模式的选型,就是软件世界的“装修决策”。面对一个需求,是直接写几行朴素的代码,还是引入工厂统一创建逻辑?是给旧接口套一层适配器,还是干脆重写?是为“以后可能的扩展”提前抽象,还是先满足当下?这些问题没有标准答案,只有一套决策的思路——正如设计师手里的卷尺和预算表。 这篇文章会带你像逛装修现场一样,把“选型”这件事拆开看:先学四把“量房尺”(原则),再看三类“装修工种”(创建型、结构型、行为型),最后学会做“预算表”(权衡)并避开“拆承重墙”(反模式)。读完你会发现,选型不是背模式目录,而是一种“克制地使用工具”的工程智慧。

岗位关联

对 AI 从业者而言,模式选型是代码评审、系统设计与技术决策的核心能力——它能让你在方案讨论会上有理有据地推荐某个模式、拒绝某个过度设计,而不是凭感觉拍板。这份判断力,正是资深工程师与熟练工的真正分水岭。

目录
  1. 可视化演示
  2. 选型总原则:先量房,再动工
  3. 创建型选型:谁来买材料
  4. 结构型选型:不动承重墙的改造
  5. 行为型选型:定好家人的协作规则
  6. 决策与权衡:做一张装修预算表
  7. 反模式陷阱:当装修变成拆家
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

选型总原则:先量房,再动工

拿到一套毛坯房,很多人的第一反应是翻装修案例、看建材清单,而不是先拿尺子量房。专业设计师却会先问三个问题:这房子给谁住?常住几个人?未来五年会不会改格局?设计模式选型也是同样的道理——拿到需求不要急着报模式名,先“量房”:需求到底多复杂、会不会变、团队能不能驾驭。量房定风格,风格服务生活,而不是让生活迁就风格。

在软件工程里,KISS(保持简单)、YAGNI(你不会需要它)、高内聚低耦合、按需引入,就是选型的“量房四问”。它们不是四条孤立的格言,而是一个统一的态度:模式的引入必须由现实中真实出现的复杂度证据驱动,而不是由对未来的幻想驱动。

KISS 要求我们选出能让“需求与实现”保持清晰映射的方案;YAGNI 专门狙击“为了也许以后会用到的扩展”而提前设计的冲动。高内聚低耦合是评估候选方案的结构性标尺——无论用不用模式,模块内部的职责要聚拢,模块之间的依赖要松弛。按需引入则是收尾原则:只有当痛点真实出现(创建逻辑失控、接口冲突、算法爆炸),才把对应的模式“请进场”。

记住这四条原则再去翻模式目录,你就像拿着户型图的设计师——不会被眼花缭乱的建材广告带偏,每一步改动都清楚自己为什么做。量房花掉的十分钟,会在之后每一个不返工的夜晚还回来。

V=E×T−D\displaystyle V = E \times T - D
一句话:模式的净价值 = 每次变更省下的成本 × 未来变更次数 − 引入模式的全部代价。算下来是正数,才值得动手。
  1. V(净价值)这是选型最终要回答的问题——引入模式到底值不值,V 大于 0 才有动手的理由。
    VV
  2. E(单次节省)未来每次修改或扩展时,模式帮我们省下的工作量,比如工厂把十处散落的创建改成一处的成本差。
    EE
  3. T(变更次数)预计未来发生需求变更的次数,活越频繁,模式的价值越能兑现。
    TT
  4. D(引入成本)开发、学习、维护模式的全部代价,包括额外的间接层,必须从收益里扣除。
    DD
  5. 乘与减先用 E × T 算出总收益,再减去 D,符号的正负直接决定这次选型的去留。
    E×T−DE \times T - D

创建型选型:谁来买材料

装修最忙的是“买材料”环节。总电闸全屋只有一扇,这是“单例”;需要板材、瓷砖、五金时,你希望有一个统一采购中心,报需求就送货上门,不必知道具体是哪家供应商,这是“工厂”;如果希望全屋材料风格统一,采购中心按“新中式”或“北欧”整套配货,这是“抽象工厂”;而厨房这种复杂项目,要按“拆旧→水电→橱柜→台面→验收”分步施工,这是“建造者”。

创建型模式解决的是“对象怎么产生”的问题。什么时候值得专门为“创建”引入一个模式?判断依据是:创建是否足够复杂、是否散落在各处、产品族是否强调统一。直接用 new 永远是最简单的起点——当创建逻辑开始“遍地开花”时,工厂才值得登场。

单例适合全局唯一、需要共享状态的场景(配置中心、连接池),但要警惕线程安全与测试困难;工厂方法把“创建哪种产品”的决定权交给子类,适合产品类型多变时收敛创建逻辑;抽象工厂进一步约束“产品族”的一致性,适合跨平台 UI 组件这类需要成套搭配的场景;建造者则面向参数多、构建步骤固定的复杂对象,比如一个需要十余项配置的 HTTP 客户端。

材料采购的本质不是“多建几个仓库”,而是“让所有人在唯一入口报需求”。当你在代码里发现十处都在手搓同一个复杂对象的创建流程,就该给装修队配一个统一采购中心了。

S=∑i=1nCi⇒S′=1\displaystyle S = \sum_{i=1}^{n} C_i \Rightarrow S' = 1
一句话:创建点从“散落 n 处”收敛到“只有工厂一处”,未来的修改影响面就坍缩了。
  1. S(变更影响面)当产品类型需要更换时,代码中会被波及的修改位置总数。
    SS
  2. Σ(求和累加)把散落在各处的创建语句逐个叠加,体现“遍地开花”时让人崩溃的修改量。
    ∑i=1n\sum_{i=1}^{n}
  3. C_i(第 i 处创建点)每一处直接调用构造逻辑的位置,都是未来修改的一颗雷。
    CiC_i
  4. ⇒ S' = 1(工厂收敛)引入工厂后所有创建请求都从工厂走,影响面从 n 处坍缩为 1 处。
    ⇒S′=1\Rightarrow S' = 1

结构型选型:不动承重墙的改造

老房子总有不如意:旧插座配不上新电器,墙面太单调想加点层次,怕陌生人进门又不便亲自接待。装修师傅有四种不需要拆承重墙的解法:转接头(适配器)、贴壁纸叠装饰(装饰器)、物业托管钥匙(代理)、前台统一接待(外观)。

结构型模式的共同点是“在不改变原有类内部结构的前提下,通过组合来扩展或适配”。它们回答的问题是:现有代码不能大改,需求却要变,怎么办?

适配器解决“接口不匹配”,把 A 的“方言”翻译成 B 听得懂的“普通话”,典型场景是接入第三方 SDK 时隔离差异;装饰器解决“功能叠加”,避免为每种组合都新建子类而导致的类爆炸,典型如 IO 流的多层包装;代理控制“访问方式”,在真实对象前加一道闸——权限校验、懒加载、远程调用都靠它;外观则给复杂子系统一个极简入口,调用方只跟一个“门面”说话。选型时先问:要解决的是“说不上话”(适配)、“想叠功能”(装饰)、“想管访问”(代理)还是“想省心”(外观)?

好的改造从不砸承重墙。结构型模式的优雅之处在于:老墙还在,功能却像壁纸一样一层层叠上去了。哪天不想要某层“壁纸”,撕掉即可,墙依然完好。

G(x)=d3(d2(d1(x)))\displaystyle G(x) = d_3\left(d_2\left(d_1(x)\right)\right)
一句话:装饰器像贴壁纸——从里到外一层层包上去,每一层只加一点新功能,互不干扰。
  1. x(原始对象)被增强的原始对象,比如一个基础的支付接口实现。
    xx
  2. d_1、d_2、d_3(装饰层)每一层都包裹上一层,各自负责一项独立的新能力,如加日志、加缓存、加告警。
    did_i
  3. 嵌套次序从最内层开始逐层向外执行,外层装饰可以“看到”内层装饰的结果,顺序决定了行为叠加的方式。
    (d2(d1(x)))\left(d_2\left(d_1(x)\right)\right)
  4. G(x)(叠加结果)最终对象同时具备所有装饰层的能力,而原始类一行代码都没改。
    G(x)G(x)

行为型选型:定好家人的协作规则

入住之后,麻烦往往不是墙和电,而是“家里人怎么配合”。晴天晒被、雨天烘干——晾衣方案要能随时换(策略);门铃一响,客厅、厨房、卧室的人都知道来客了(观察者);装修工序有固定套路——基层处理、刷底漆、刷面漆、验收,细节各家不同但骨架一致(模板方法);同样一扇门,开着、关着、反锁时的行为完全不同(状态)。

行为型模式管的是“对象之间的职责分配与协作方式”。它们不改变类的结构,而是重新安排“谁在什么时机做什么”。

策略模式把一族可互换的算法封装起来,让上下文在运行时切换,典型如促销计价、排序算法;观察者模式定义一对多的依赖,主题状态一变就通知所有订阅者,典型如事件总线、消息通知;模板方法把不变流程固化为骨架,把变化点留给子类,典型如数据迁移流程;状态模式把状态相关的行为内聚到各自的状态类中,消灭大量 if-else,典型如订单状态流转。选这四个模式的关键是看“变化的主角是谁”:算法?通知?流程?还是状态?

行为协作的选型,本质是在给家庭成员发“分工说明书”:不变的流程用模板固化,会变的部分抽出来让策略自由替换。家里从此井然有序,来再多的客人也不乱。

result(x)=sk(x),sk∈{s1,s2,…,sn}\displaystyle \mathrm{result}(x) = s_k(x), \quad s_k \in \{s_1, s_2, \dots, s_n\}
一句话:策略模式把“用哪个算法”变成一道选择题,运行时按下开关就能换,不用改上下文。
  1. s_k(当前策略)正在被选中的那个算法实现,k 表示它在策略家族中的下标。
    sks_k
  2. 策略家族一组可以互换的算法,比如折扣计价、满减计价、返券计价,它们实现同一个接口。
    {s1,s2,…,sn}\{s_1, s_2, \dots, s_n\}
  3. x(上下文输入)调用方传进来的业务数据,无论选哪个策略,输入格式保持一致。
    xx
  4. result(执行结果)当前策略处理后的输出——选晴天方案就晾被,选雨天方案就烘干,结果都是“衣服干了”。
    result(x)\mathrm{result}(x)

决策与权衡:做一张装修预算表

方案定了好几个,最终拍板靠什么?靠预算表。每一项装修增项都写清楚:这房间未来改不改(扩展性)、师傅会不会做(团队熟悉度)、报价多少(复杂度代价)、对居住体验影响多大(性能)。把所有候选方案算一遍总分,最高者中标——注意,中标的不一定是材料最贵的,而是总分最高的。

模式选型的最后一步是量化比较。除了“这个模式能不能解决问题”,还要比较“值不值得为它付出代价”。工程决策从来不是单选题里的唯一正确项,而是加权后的相对最优解。

决策维度通常包括:需求匹配度——模式是否精准命中痛点;扩展性预期——依据真实业务规划而非臆测;性能影响——间接层带来的调用开销是否可接受;维护成本——间接层越多,排查问题越绕;团队熟悉度——没人会的“高级模式”就是负资产。把这些维度加权汇总,得到可比较的分数。同时记住“两害相权”:模式引入的间接性与调试难度,往往比多写几行朴素代码更贵。

预算表的价值不是算出“精确的正确”,而是逼你把每个方案的代价摆到桌面上。装修不超支的秘诀从来不是少花钱,而是每分钱都花得明白。

Score=w1X+w2E+w3M−w4C\displaystyle \mathrm{Score} = w_1 X + w_2 E + w_3 M - w_4 C
一句话:给每个候选模式打分——扩展性、匹配度、团队熟练度加分,复杂度代价减分,总分最高者胜出。
  1. X(扩展性需求)基于真实业务规划评估的未来变化强度,而不是“也许有一天”的脑补。
    XX
  2. E(场景匹配度)模式与当前需求痛点的契合程度,匹配越精准得分越高。
    EE
  3. M(团队熟悉度)团队对该模式的掌握水平,陌生模式意味着学习和踩坑成本。
    MM
  4. C(复杂度代价)模式带来的间接层、调试难度和性能开销,这一项要作为减分处理。
    CC
  5. 权重 w每个维度的权重由项目上下文决定——快节奏创业项目可能更看重 E,长期维护型系统更看重 C 的惩罚。
    wiw_i

反模式陷阱:当装修变成拆家

见过最惨的装修翻车:为了“以后可能装电梯”,提前在一楼砸出电梯井,结果验收不过、全楼返工;或者师傅手里只有一把锤子,看啥都像钉子,好好的墙面也要敲两下。装修的灾难很少因为“做少了”,大多因为“做过头了”。

软件工程把这些“做过头”的实践称为反模式。它们看起来很有道理——提前考虑扩展、全面应用模式、追求设计完备——实际上却在给未来制造债务。

常见反模式:过度设计——在简单需求上堆砌抽象层,为臆想的未来买单;模式滥用——把单例当全局变量的遮羞布、把策略模式用在两个固定分支上;忽视简单方案——为了“专业感”拒绝用朴素代码;锤子心态——熟练一种模式后到处套用。技术债务的可怕之处在于它不是线性增长:方案复杂度超出需求越多,债务膨胀得越快。

守住反模式的底线很简单:每次想加一层抽象时,先问自己——这是需求逼我做的,还是我的“职业习惯”逼我做的?装修如此,写代码亦如此。拆过的承重墙,永远不会自己长回来。

D=α(C−N)2\displaystyle D = \alpha \left(C - N\right)^2
一句话:债务与“方案复杂度和需求复杂度的差值”的平方成正比——超出越多,爆雷越快。
  1. D(技术债务)未来重构、解释、修 bug 时付出的总代价,是过度设计积累的账单。
    DD
  2. C(方案复杂度)你实际采用的方案的复杂程度,抽象层、间接调用、配置项越多,C 越大。
    CC
  3. N(需求复杂度)当前需求真正需要的复杂程度,简单需求 N 很小。
    NN
  4. 平方(非线性放大)差值每扩大一倍,债务膨胀四倍——这正是“过度设计”比“少设计”危险得多的原因。
    (C−N)2\left(C - N\right)^2
  5. α(环境系数)团队流动率、文档缺失程度等放大债务的外部因素,团队越不稳定,α 越大。
    α\alpha

AI 应用场景

场景一:微服务架构中的事件通知选型

阶段:架构设计 / 技术选型

解决的问题:传统做法是订单服务直接 RPC 调用库存、积分、物流的接口,形成强耦合的调用链——每加一个下游系统,订单服务就要改一次代码。借鉴“观察者”思想引入事件总线后,订单状态变更只需发布事件,各系统自行订阅,彻底解开耦合。

具体案例:某电商平台订单“已支付”事件被库存、积分、短信、发票四个系统同时订阅。后来新增一个审计系统,只需加一个订阅者,订单服务零改动。这正是观察者模式“一对多松耦合通知”在微服务架构中的落地。

场景二:遗留支付系统的适配器改造

阶段:重构 / 兼容性改造

解决的问题:老支付网关接口与新交易系统不兼容,直接重写旧系统风险高、周期长。用适配器在老接口外包一层“翻译层”,新系统无需理解旧协议,旧系统也一行不改。

具体案例:银行升级核心系统后,旧 POS 终端协议不能变。工程师编写适配器,把新系统报文实时翻译成旧协议,POS 端零改动平滑过渡,避免了数月的停机迁移。

场景三:大模型应用的接入策略切换

阶段:模型接入 / 路由决策

解决的问题:AI 应用常需在多个大模型(不同厂商)间切换,直接用 if-else 判断厂商会让调用逻辑膨胀难维护。用策略模式为每家模型封装一个“调用策略”,按成本、延迟、效果动态切换。

具体案例:AI 客服系统同时接入三家大模型,简单问题路由到低价模型,复杂问题路由到强模型。新增一家模型厂商时,只需实现同一个策略接口,调用方完全不需要改动。

Python 演示

python44 行
#!/usr/bin/env python3# 设计模式选型决策器: 根据需求特征评分, 推荐最匹配的模式 PATTERN_PROFILES = {    # 模式名 -> {需求特征: 权重}    "Singleton": {"unique_state": 3, "shared_state": 2, "many_creates": 1},    "Factory":   {"complex_create": 3, "multi_impl": 2, "decouple_call": 1},    "Adapter":   {"iface_mismatch": 3, "reuse_legacy": 2, "compat_old": 1},    "Strategy":  {"algo_variant": 3, "avoid_branches": 2, "switch_runtime": 1},    "Observer":  {"one_to_many": 3, "loose_couple": 2, "event_driven": 1},    "Decorator": {"dynamic_boost": 3, "avoid_explosion": 2, "transparent_add": 1},}  def recommend(needs, top_n=3):    # needs: 需求特征字典, 值为 True 或权重系数    scores = []    for name, profile in PATTERN_PROFILES.items():        total = 0        matched = []        for feature, weight in profile.items():            val = needs.get(feature, 0)            if val:                total += weight * (1 if val is True else val)                matched.append(feature)        scores.append({"pattern": name, "score": total, "matched": matched})    scores.sort(key=lambda x: x["score"], reverse=True)    return scores[:top_n]  def main():    # 场景1: 全局配置中心, 状态全局唯一且需要共享    case_1 = {"unique_state": True, "shared_state": True}    # 场景2: 支付渠道切换, 算法多变且需运行时替换    case_2 = {"algo_variant": True, "avoid_branches": True}    for tag, needs in [("global_config", case_1), ("payment_switch", case_2)]:        print("scenario:", tag)        for r in recommend(needs):            print("  %-10s score=%d matched=%s" % (r["pattern"], r["score"], r["matched"]))        print()  if __name__ == "__main__":    main()
目的:这是一个“模式选型评分器”——把需求特征喂进去,它按每个模式的画像加权打分,输出 Top 3 推荐,让选型从“拍脑袋”变成“算分数”。
  1. PATTERN_PROFILES = {...}定义了每个模式的“画像”:它擅长解决哪些需求特征,权重表示适配程度,对应正文里的模式选型知识库。
  2. for feature, weight in profile.items():遍历某个模式的全部特征,逐一核对当前需求是否命中。
  3. val = needs.get(feature, 0)安全地读取需求特征值,缺失时按 0 处理,不会因为缺 key 报错。
  4. total += weight * (1 if val is True else val)命中就加权计分;如果调用方给了自定义权重系数,就按系数放大。这正对应“决策与权衡”的加权评分公式。
  5. scores.sort(key=lambda x: x["score"], reverse=True)按总分从高到低排序,最高分的模式就是“预算表”上性价比最好的候选。
  6. for tag, needs in [("global_config", case_1), ...]一次性跑多个测试场景,验证决策器输出是否符合人工判断——全局配置中心应命中单例,支付切换应命中策略。

常见误区

误区很多新手觉得代码里出现工厂、单例就代表专业,写代码时先想“这里该套什么模式”,而不是先想“需求到底是什么”。面试时也习惯先报几个模式名壮胆。

正解模式是对反复出现问题的经验总结,是为需求服务的工具,不是目的。就像装修,豪华建材堆满屋不叫好设计,住得舒服才是。优秀的代码是恰好满足当前需求的代码——量房之后,需要什么才装什么,这是正文“选型总原则”的核心态度。

为何常见:课程、书籍和面试都在反复强调模式,容易让人把“会用模式”当成能力的象征,而忘了模式只是工具箱里的工具。

误区以为“保持简单”等于把代码行数压到最少,于是用各种奇技淫巧压缩代码,结果可读性反而更差,别人完全看不懂。

正解KISS 的“简单”指结构简单、易于理解和维护,而不是行数最少。就像刷白墙住得舒服,但为了省材料把承重墙敲掉,就是用安全换“简单”。判断标准是:一个新人接手这段代码,能不能快速读懂并在三分钟内找到修改点。

为何常见:把“简单”错误地量化为行数或类数量,忽略了“人理解的复杂度”才是真正的复杂度指标。

误区以为未来一定会扩展,于是把工厂、策略、观察者、装饰器全部铺上,觉得“全副武装”最稳妥,代码里全是抽象层。

正解每个模式都是一层间接,都会增加理解成本和调试难度。YAGNI 提醒我们不为不确定的未来提前买单。全屋装智能家居,结果没人会用、坏了难修,反而不如几盏正常的灯。正文的净价值公式 V = E×T − D 也说明:几乎不发生变更的代码,E×T 趋近于零,任何模式都是亏本买卖。

为何常见:对未来的不确定性感到恐惧,用“周全设计”来安抚焦虑,却忽视了过度设计的隐性成本——技术债务是指数增长的。

误区技术选型时只算复杂度、扩展性这些“硬指标”,完全不考虑团队熟不熟悉。觉得“模式是对的,学就是了”。

正解团队熟练度直接影响引入成本 D。一个没人懂的“优雅方案”,落地时 bug 多、评审慢、核心人员一离职就失传,净价值 V 很可能为负。装修师傅没做过微水泥,硬要做就是翻车现场。选型时一定要把团队因素加权进评分公式,而不是事后才补课。

为何常见:技术人员容易把“理论上正确”等同于“工程上最优”,忽略了人——写代码的人、维护代码的人——才是软件系统里最不可控的一环。

面试题

Q1. 面对一个只展示静态数据的页面模块,按选型总原则应如何选择?

单选题 · easy

  • A.用最简单的方案满足当前需求← 正确答案
  • B.引入更多设计模式稳妥可靠
  • C.提前为扩展预留抽象接口
  • D.尽可能压缩代码的总行数

答案:A。需求简单且没有变化迹象时,KISS 原则要求用最朴素的方案直接实现,不要提前抽象。B 违背“按需引入”,C 违背 YAGNI,D 是对 KISS 的误解——KISS 追求的是结构简单而非行数少。

Q2. 全局配置中心要求配置信息全局唯一且共享,最合适的选择是?

单选题 · easy

  • A.使用单例管理全局唯一状态← 正确答案
  • B.每次请求都新建一个对象
  • C.用抽象工厂创建产品族
  • D.通过观察者广播状态变化

答案:A。单例模式的适用边界正是“全局唯一 + 共享状态”,像全屋只有一个总电闸。每次新建对象会丢失共享状态;抽象工厂管的是产品族一致性;观察者管的是通知协作,都与“唯一”无关。

Q3. 新旧两套系统接口不兼容,旧模块不能改动,最佳选择是?

单选题 · mid

  • A.重写旧系统的全部业务逻辑
  • B.使用适配器转换接口的差异← 正确答案
  • C.使用装饰器叠加新的功能层
  • D.使用代理拦截外部访问请求

答案:B。适配器专门解决“接口不匹配”,像转接头一样把新旧两套协议“翻译”通,旧模块零改动。重写风险高,装饰器管功能叠加,代理管访问控制,都不解决“说不上话”的方言问题。

Q4. 策略模式最核心的价值是什么?

单选题 · easy

  • A.消除大量多变的条件分支← 正确答案
  • B.保证系统只有一个实例
  • C.转换两个不兼容的接口
  • D.把复杂构造拆成多步骤

答案:A。策略模式把一族可互换的算法封装起来,让上下文在运行时切换,从而消灭“算法一变就加 if-else”的分支膨胀。B 是单例,C 是适配器,D 是建造者。

Q5. 模式选型时,属于“决策与权衡”应考察的维度有?

多选题 · mid

  • A.扩展性需求的强弱程度← 正确答案
  • B.团队对模式的熟悉程度← 正确答案
  • C.引入后的维护成本高低← 正确答案
  • D.代码注释的数量是否足够

答案:ABC。扩展性(X)、团队熟悉度(M)、复杂度代价(C)都是评分公式里的正式维度。注释数量与模式选型没有因果关系——注释充足是好习惯,但不是选型考量的技术维度。

Q6. 工厂方法模式最适合解决什么问题?

单选题 · mid

  • A.对象创建逻辑复杂且类型多变← 正确答案
  • B.多个对象之间存在一对多通知
  • C.需要给对象动态叠加新能力
  • D.需要统一一批流程的固定骨架

答案:A。工厂的用武之地就是“创建逻辑复杂、产品类型多变”——把遍地开花的创建语句收敛到一个入口。B 是观察者,C 是装饰器,D 是模板方法。

Q7. 下列哪种现象是“过度设计”的典型信号?

单选题 · hard

  • A.为未来扩展提前加入大量抽象← 正确答案
  • B.用简单函数直接实现当前需求
  • C.用适配器隔离第三方接口差异
  • D.用策略替换复杂多变的条件分支

答案:A。过度设计是“用臆想的未来需求驱动当下的复杂度”,抽象层越多维护越难,技术债务按差值的平方膨胀。B 符合 KISS,C 和 D 都是模式在正确场景下的合理应用。

Q8. 下列哪些场景不适合引入新的设计模式?

多选题 · hard

  • A.需求非常简单且几乎没有变化← 正确答案
  • B.团队对候选模式完全不熟悉← 正确答案
  • C.需求即将被彻底重构或删除← 正确答案
  • D.创建过程复杂且重复出现频率高

答案:ABC。简单无变化的需求用朴素代码即可(A);团队不熟导致引入成本 D 巨大(B);即将被重写的代码引入模式是纯浪费(C)。D 恰恰是工厂模式的理想场景,属于应该引入的情形。

Q9. 观察者模式最适合以下哪种业务场景?

单选题 · mid

  • A.订单状态变更通知多个下游系统← 正确答案
  • B.支付渠道的统计算法运行时切换
  • C.兼容遗留协议并转换新旧接口
  • D.复杂对象的参数逐步构建与组装

答案:A。观察者定义“一对多”的依赖通知,主题一变化就广播给所有订阅者,正是订单事件通知库存、积分、短信的场景。B 该用策略,C 该用适配器,D 该用建造者。

Q10. 关于“锤子心态”,以下说法正确的是?

多选题 · extreme

  • A.熟练一种模式之后便到处套用← 正确答案
  • B.属于反模式家族中的模式滥用← 正确答案
  • C.会鼓励团队禁用所有设计模式
  • D.容易忽略更简单的朴素实现方案← 正确答案

答案:ABD。锤子心态指手里只有一把锤子,看什么都像钉子——熟练某模式后到处套用(A),这正是模式滥用的一种(B),且会让人忽视朴素方案(D)。它不会“鼓励禁用模式”,反而恰恰阻碍了“按需引入”的正确判断,因此 C 错误。