写程序这事儿,外行看着像“敲代码”。内行知道,它更像“做菜”。
同一道菜,你可以清炒、红烧、做汤、做凉拌。
都能吃,但口感、成本、出菜速度、翻车概率完全不一样。
设计方法也是同理:
同一个需求,你可以用面向过程、面向对象、领域驱动、测试驱动、事件驱动……各种“做法”。
它们不是互相打架的宗派,而是解决不同问题的工具箱。
这篇文章就用大白话把这些常见设计方法讲明白:
- 它们分别在解决什么问题
- 各自适合什么场景
- 用不好会怎么翻车
- 在真实项目里怎么组合使用(重点:组合)
你看完至少能做到:需求来了,不会条件反射“我就用 OO/我就上 DDD”,而是能判断:这次到底该用哪套打法。
1. 先把概念捋顺:设计方法 vs 设计原则 vs 设计模式
很多人一上来就混了。先用一句话分清:
- 设计原则:写代码的“交通规则”(KISS、DRY、SOLID…)
- 设计模式:常见问题的“套路解法”(策略、观察者、工厂…)
- 设计方法:看世界的“组织方式/建模方式/工作方式”(面向过程、面向对象、DDD、TDD…)
打个比方:
- 原则:厨房卫生要求、刀具怎么用更安全
- 模式:宫保鸡丁怎么做有套路
- 方法:你是中餐做法、西餐做法、还是预制菜流水线
所以本文讲的是“方法”:你用什么方式去组织系统、组织代码、组织协作。
2. 面向过程:像写菜谱一样写程序(最朴素、最直观)
2.1 面向过程是啥?
面向过程就是:把一个问题拆成一系列步骤,按顺序执行。
典型长相:
- 读输入
- 处理
- 输出结果
- 结束
你可以理解为“流水账式做事”。
2.2 它的优点(它为什么一直活到今天)
- 简单直接,上手快
- 逻辑线性,易于追踪
- 适合小工具、小脚本、一次性任务
- 性能可控(少一层抽象)
你写一个“批量改文件名”“导表生成配置”“把日志转成报表”——面向过程非常香。
2.3 它的缺点(项目一大就容易长成面条)
如果业务变复杂,面向过程容易变成:
- 一个巨大函数里全是 if-else
- 状态散落在全局变量
- 改一个功能影响一串流程
像什么?像你把耳机线放口袋:刚放进去很顺,拿出来就是一坨结。
2.4 适用场景
- 脚本、工具、数据处理
- 功能很明确、变化很少
- 逻辑就是“一条流水线”
3. 面向对象(OO):把世界拆成“对象”,让对象各司其职
3.1 面向对象是啥?(一句人话)
面向对象的核心不是“类”“继承”这些词,而是:
把系统拆成一群“有责任的角色”,
每个角色管自己的事,通过协作完成任务。
你可以把它想成一家公司:
- 采购负责采购
- 财务负责付款
- 仓库负责出入库
- 客服负责接电话
你不会让“客服去搬货”,也不会让“仓库做账”。
3.2 OO 的三板斧:封装、继承、多态(大白话版)
- 封装:别人的事你别管,你只管给我一个能用的接口
- 继承:我和你很像,我复用你的能力再加点新能力(但很容易滥用)
- 多态:同一个“命令”,不同对象做不同事(扩展性来源)
很多人 OO 写不好,问题出在:
把“面向对象”写成了“面向类名编程”,类堆了一堆,责任没分清。
3.3 OO 的优点
- 适合表达长期演进的业务
- 便于扩展:新增一种类型/策略时,不一定要改旧代码
- 责任更清晰,协作更自然
- 可测试性更强(如果你设计得当)
3.4 OO 的常见翻车方式
- 上来就继承:继承树像族谱,改一下爹,全家遭殃
- 上帝类:
GameManager什么都管 - 贫血模型:对象只存数据,逻辑全在 Service 里,最后还是过程式泥浆
- 为了 OO 而 OO:本来两函数能解决,非要搞 10 个类
3.5 适用场景
- 中大型业务系统
- 需求变化频繁
- 多人长期维护
- 需要扩展点(支付方式、结算规则、技能效果等)
4. 领域驱动设计(DDD):先把业务说清楚,再写代码(尤其适合复杂业务)
4.1 DDD 是啥?别被名字吓到
DDD 很多教程一上来就:
- 聚合根
- 值对象
- 领域事件
- 防腐层
- 限界上下文
听得人头皮发麻。
你先记住 DDD 的核心人话就够了:
DDD 就是:
用业务语言建模,让代码结构贴着业务走;
并且把不同业务边界隔开,别搅成一锅粥。
DDD 解决的是“业务复杂导致代码复杂”的问题。
当规则很多、名词很多、例外很多时,光靠 OO 也容易写乱。
4.2 DDD 最有价值的两件事
4.2.1 统一语言(Ubiquitous Language)
产品说“订单关闭”,你理解成“取消”;运营说“作废”;客服说“退单”。
最后系统里出现了:CloseOrder、CancelOrder、VoidOrder 三套逻辑,各说各话。
DDD 强调:
业务名词要统一,写进代码里,大家说同一种话。
4.2.2 限界上下文(Bounded Context)
比如“用户”这个词:
- 在账号系统里:登录身份
- 在电商系统里:收货人、购买历史
- 在风控系统里:风险画像
它们叫同一个词,但含义不同。
DDD 说:别把这几个“用户”揉成一个巨型 User 类。
要隔开:各自一套模型,各自负责各自的事。
4.3 DDD 的优点
- 面对复杂规则不容易写成一坨 if-else
- 边界清晰,微服务拆分更有依据
- 沟通成本下降(业务和技术对齐)
- 代码更像业务说明书(可读性提升)
4.4 DDD 的代价与坑
- 学习成本高,容易“概念先行”
- 小项目硬上 DDD,会变成“写模型写爽了,功能没交付”
- 如果组织/团队没配合好(业务方不参与建模),DDD 会沦为“架构师自嗨”
4.5 适用场景
- 业务规则复杂:优惠、结算、风控、库存、结算对账
- 多团队协作:边界不清就扯皮
- 需要长期演进:不是三个月就扔的项目
- 计划做微服务拆分:DDD 的上下文边界很有用
5. 测试驱动开发(TDD):先写“验收标准”,再写实现
5.1 TDD 是啥?一句话
TDD 的核心不是“测试”,而是:
先把你想要的行为写成可执行的标准(测试),
再写代码让它通过。
流程一般叫“红-绿-重构”:
- 写测试(红:失败)
- 写最少代码让它通过(绿:成功)
- 重构代码保持测试都绿
5.2 TDD 的优点(真实收益)
- 强迫你把需求想清楚(输入输出边界明确)
- 代码天然更可测试(设计会更松耦合)
- 重构更有底气(测试就是安全绳)
- 长期维护成本下降
5.3 TDD 的常见误解
“TDD = 测试很多很烦”
不对,TDD 是“用测试推动设计”,不是写一堆无意义断言。“我先写完再补测试也一样”
差别大:先写实现往往会写得耦合很紧,后补测试会很痛苦,导致你不补。
5.4 适用场景
- 核心业务逻辑(计算、规则、状态机)
- 容易出错、回归代价高的模块
- 团队愿意投入质量建设
不太适合:强 UI 驱动、强依赖外部系统且难以隔离的地方(但也不是完全不能做)
6. 行为驱动开发(BDD):让业务也看得懂的“测试”
BDD 可以理解成 TDD 的“更面向业务版本”。
它通常用“Given-When-Then”描述:
- Given:前置条件
- When:触发行为
- Then:期望结果
好处是:测试用例看起来像需求文档,产品、测试也能参与。
适用:
- 需求频繁变化、需要可追溯的验收标准
- ToB 系统、流程类系统
- 质量要求高的业务
7. 事件驱动(EDA):别总“打电话”,可以“发广播”
7.1 人话解释
传统系统像打电话:A 调 B,B 再调 C。耦合很强。
事件驱动像发广播:A 发生了“订单已支付”事件,谁关心谁订阅。
7.2 优点
- 解耦:发布者不知道谁在听
- 易扩展:加一个订阅者就能新增功能
- 适合异步流程:发货、积分、通知、对账
7.3 代价
- 调试更难(链路长、异步)
- 一致性更复杂(重复消费、幂等)
- 需要消息基础设施与治理(MQ、重试、死信队列)
8. 数据驱动/表驱动:把“if-else”变成“配置”
很多复杂逻辑其实是规则组合,比如游戏技能、怪物 AI、活动策略。
把规则写成配置/表,代码写成解释器或执行器,这就是表驱动思想。
优点:
- 改规则不改代码
- 运营/策划能参与
代价: - 配置系统要做校验与工具链,否则会“配表配到崩溃”
9. 组件化/模块化:把系统切成“积木”
组件化更像工程管理方法:
把 UI、网络、资源、账号、支付做成独立模块,明确边界和依赖方向。
优点:
- 并行开发
- 复用
- 降低冲突
代价: - 需要规范(接口、版本、依赖)
- 模块过细会变成“拆得太碎,沟通爆炸”
10. 这些方法是互斥的吗?不是,它们经常是“混搭套餐”
现实项目里常见组合是:
- 整体偏面向对象:业务用对象协作表达
- 复杂业务用 DDD:统一语言 + 边界隔离
- 核心逻辑用 TDD/BDD:保证稳定、可重构
- 跨模块协作用事件驱动:解耦、异步
- 规则变化多的用表驱动:减少发版
你可以把它看成:
面向对象是“日常主食”,DDD 是“复杂菜系”,TDD 是“食品安全流程”,事件驱动是“外卖配送体系”。
11. 怎么选设计方法?给你一套“傻瓜判断法”
11.1 需求简单、生命周期短、就一个人维护
- 面向过程 + KISS
别上来搞大架构。
11.2 功能开始变多、多人协作、需要扩展点
- 面向对象(注意 SRP、OCP)
把责任分清楚。
11.3 业务规则爆炸、名词混乱、跨团队扯皮
- DDD(至少做统一语言 + 上下文边界)
不一定要全套战术,但边界要先谈清楚。
11.4 你们经常改出回归 bug、怕重构
- TDD(先从核心模块、小范围开始)
别幻想“一夜全站 TDD”,从最痛的地方推进。
11.5 模块之间联动多、异步流程多
- 事件驱动(先把事件命名、幂等、追踪做好)
否则会变成“分布式玄学”。
12. 最后给点“防走火入魔”的忠告(非常重要)
12.1 设计方法不是宗教
别变成:
- “不用 DDD 就是不专业”
- “不 TDD 就是代码不行”
现实世界是成本与收益的权衡。
12.2 先解决问题,再选择方法
方法是工具,不是目的。
你要的是:
- 少 bug
- 好迭代
- 好维护
不是要“看起来像大厂架构”。
12.3 从小处开始落地
比如:
- 先用 SRP 把“神类”拆掉
- 先用 TDD 覆盖一个最核心的规则计算模块
- 先用事件把“支付成功后的一堆联动”解开
一步一步来,收益更真实。
总结:一句话把这些方法全串起来
- 面向过程:按步骤做事,简单直接
- 面向对象:按角色分工,对象协作
- DDD:业务复杂时先建模、先统一语言、先定边界
- TDD/BDD:用可执行的验收标准推动设计,给重构上保险
- 事件驱动:用事件解耦系统联动,适合异步扩展
- 表驱动/数据驱动:把规则从代码搬到配置,让变化更便宜
- 组件化/模块化:工程上切积木,提升协作与复用
你真正需要记住的不是名词,而是这个思路:
设计方法 = 选择一种组织方式,让“变化”更便宜。
便宜到你敢改、敢重构、敢交接,系统也不怕折腾。