复用的对象从代码行变成独立部署的构件,软件开发的经济学就变了。
“购买,而非建造”
CBSE(Component-Based Software Engineering,基于构件的软件开发)的核心思想一句话就能概括:能买到的,就不要自己写。
传统开发里我们复用函数、复用库;CBSE 把复用的粒度提高到构件(Component)——独立部署、有明确契约、可被第三方组装的软件单元。开发方式从“建造”变成“组装”:需求确定后,先看货架上有什么,买回来拼起来,剩下的缺口才自己补。
这个转变的背后是经济学:构件一旦被多个项目复用,边际成本趋近于零,而质量已被前面的项目验证过。
常见实现
| 技术 | 年代 | 形态 |
|---|---|---|
| OMG / CORBA | 90 年代 | 跨语言分布式对象,ORB 总线通信 |
| EJB | 90 年代末 | Java 企业级构件,容器托管事务、安全等基础设施 |
| COM / COM+ | 微软系 | 二进制级组件规范,Windows 平台复用 |
CORBA 的愿景是“语言无关、平台无关”,最终败给了重量级和互操作性地狱;EJB 把基础设施(事务、安全、池化)交给容器,思想被 Spring 继承了下来;COM 证明了二进制兼容契约的价值。今天来看,微服务、npm 包、容器镜像,都是 CBSE 思想在不同时代的化身。
CBSE 过程
CBSE 不是瀑布的替代品,而是一条围绕“可复用构件”重新编排的流程:
系统需求概览 ──► 识别候选构件 ──► 根据构件修改需求
│ │
│ ▼
│ 体系结构设计
│ │
│ ▼
└────────────────────────── 构件定制与适配
│
▼
组装构件,创建系统
六个步骤里有两个是 CBSE 独有的动作:识别候选构件(在动手前先盘点货架)和根据构件修改需求(让需求迁就可复用的现实)。
与传统开发过程的不同
- 需求要早,但要可改。传统流程早期需求必须完整;CBSE 同样要求早期给出需求概览——目的是尽可能多地识别出可复用构件——但后续要根据实际发现的构件细化和修改需求。
- 需求向构件低头。不是所有需求都值得实现,如果货架上有一个覆盖 80% 功能的构件,剩下 20% 的需求可能被改写甚至砍掉。
- 架构设计是枢纽。体系结构设计完成后仍可能反过来修改构件,使其适配功能和架构;架构本身也决定并限制了可选构件的范围——选错架构,货架上一半构件用不了。
- 开发即组装。开发过程的主体是组装构件,缺口处才写代码,还常常需要开发适配器把不兼容的接口缝合起来。
构件组装
常见的组装方式有三种:
- 顺序组装:构件 A 的输出作为构件 B 的输入,像流水线;
- 层次组装:下层构件向上层提供服务,上层调用下层,典型的分层架构;
- 叠加组装:多个构件叠加组合,共同完成一个功能,比如一个界面由多个视图构件拼成。
顺序组装: [A] ──输出──► [B] ──输出──► [C]
层次组装: ┌─────────┐
│ 上层构件 │ 调用
├─────────┤
│ 下层构件 │ 提供服务
└─────────┘
叠加组装: ┌─────┬─────┐
│ 构件1 │ 构件2 │ ──► 组合功能
└─────┴─────┘
接口不兼容与适配器
组装时最常踩的坑是接口不兼容,主要有三类:
- 参数不兼容:同名操作的参数类型或个数对不上;
- 操作不兼容:一个构件提供的操作和另一个期望的名称、签名不一致;
- 操作不完备:需要的操作对方根本没提供。
解法是编写适配器构件(Adapter):在不改动原构件的前提下,做参数转换、接口转译或补齐缺失操作,把两个构件的契约缝合起来。适配器是 CBSE 的“胶水代码”,也是组装成本的主要来源。
小结
CBSE 的价值不在于某个具体技术(CORBA 早已作古),而在于它把“复用”从技巧上升为工程经济学:先盘点货架,再决定建造什么。今天选型时问一句“这个需求有没有现成的构件/服务/包”,就是 CBSE 思想最日常的实践。