软件设计基础:抽象、模块化与接口

先看两种代码。 A 模块里:查订单、算运费、写数据库、发邮件、记日志全挤在一起,改一个「运费规则」要在一千行里找半天,还怕动到发邮件那几行。B 模块里:订单、运费、通知、持久化各是一块,每块只暴露「我要什么、我给你什么」的接口;改运费只要进「运费计算」这一块,其它不动。差别不在谁更聪明,而在有没有做抽象、模块化和接口分离——把「本质」留下、把「细节」藏起来,把系统拆成边界清晰、通过约定协作的模块。本章讲软件设计的三个基础:抽象(保留本质、隐藏细节)、模块化与高内聚低耦合接口与实现分离,以及设计如何影响后续开发与维护成本

一、抽象:保留本质、隐藏细节

抽象(Abstraction)是在思考或表达时,只关注当前层次关心的东西,把其余当作「黑盒」忽略掉。用一句话说:保留本质、隐藏细节。例如「存储」:调用方只关心「存进去、取出来」,不关心是存在文件、数据库还是内存;「发送通知」只关心「发给谁、发什么」,不关心走邮件还是短信还是推送。抽象层次选对了,读代码、改代码都能「一次只面对一层复杂度」。

抽象:调用方只依赖「存/取」;实现可以是文件、数据库或缓存

抽象不是「少写代码」,而是划清层次:上一层只依赖下一层的「能做什么」(接口),不依赖「怎么做」(实现)。这样换实现(例如存储从文件换成数据库)时,只要新实现满足同一接口,上层不用改。抽象不足会「什么都掺在一起」;过度抽象会「为了抽象而抽象、增加理解成本」——要按实际变化点来选抽象层次。

二、模块化与高内聚低耦合

模块化是把系统拆成一块一块(模块),每块有相对清晰的职责边界。高内聚:模块内部「为一类事服务」、相关逻辑聚在一起。低耦合:模块之间依赖少、接口小、改一块尽量不牵动其它块。高内聚低耦合是衡量「拆得好不好」的经典标准。

低内聚、高耦合
  • 模块内职责混杂,改一处要动很多行
  • 模块间互相直接调实现、传大量参数
  • 改 A 可能影响 B、C、D,难以定位与测试
高内聚、低耦合
  • 模块内「一类事」聚在一起,职责单一
  • 模块间通过少量、稳定的接口协作
  • 改一块影响范围清晰,易测、易维护
模块化目标:高内聚(块内一致)、低耦合(块间简单)

实践上:按职责或变化原因划分模块(例如「订单」「支付」「通知」分开);模块间只通过公开接口通信,不跨模块直接碰内部数据结构;依赖方向一致(例如业务层依赖数据层,而不是反过来),避免循环依赖。这样后续加功能、修 bug、换实现,都能控制在少数模块内。

三、接口与实现分离

接口是对外暴露的「能做什么」的约定(函数签名、API、协议);实现是「具体怎么做」的代码。分离的意思是:调用方依赖接口而不是实现。这样换实现(例如从 MySQL 换成 PostgreSQL)、加新实现(例如多一种存储方式)、做测试时用 Mock 实现,都不用改调用方。

接口与实现分离:调用方依赖接口;实现 A/B 可替换

在代码里:用接口类型(或抽象类、协议)声明依赖,注入具体实现(构造注入、参数传入等);不要在上层代码里 new 具体实现类,否则就绑死了。这样单元测试可以注入假实现,生产环境注入真实实现,扩展新实现也不影响已有调用方。

四、设计如何影响后续开发与维护成本

设计不是「一次性画完图就完事」,它直接决定后续每次改动的成本。设计得好:改需求时影响范围小、易定位、易测、敢重构;设计得差:改一处牵一发动全身、不敢动、只能打补丁,时间越久成本越高。

开发成本
模块清晰、接口稳定时,新功能多是在边界内加代码;反之则到处找、到处改、易引入回归。
测试与定位
高内聚低耦合便于单测和隔离;接口分离便于 Mock。耦合高则难测、问题难定位。
演进与重构
抽象与接口为「换实现、加新实现」留空间;边界清晰时重构风险可控。
设计质量影响:开发效率、测试与定位、演进与重构
设计好则随时间的改动成本可控;设计差则越改越贵

一句话: 抽象是「保留本质、隐藏细节」,让每一层只面对当前层次的复杂度。模块化要高内聚低耦合:块内职责清晰、块间通过少量接口协作。接口与实现分离让调用方依赖约定而非具体实现,便于替换、测试与扩展。好的设计会持续降低后续开发与维护成本;差的设计会让每次改动越来越贵。

小贴士: 写代码时多问两句:「这块如果以后要换成另一种实现,要改多少地方?」「如果另一个同事只改这一块,会不会误伤别的功能?」若答案都是「很少/不会」,说明抽象和边界大致合理。

五、小结

抽象是保留本质、隐藏细节,划清层次、让上层只依赖「能做什么」。模块化追求高内聚(块内一致)、低耦合(块间简单),按职责或变化原因划分、依赖方向一致。接口与实现分离让调用方依赖接口,实现可替换、可 Mock、可扩展。设计质量直接决定后续开发、测试、定位和重构的成本;设计好则长期成本可控,设计差则越改越贵。下一章我们讲面向对象分析与设计(OOAD)入门:对象、类与封装,职责划分与单一职责,继承、组合与多态。