引言:一个奇怪的哲学问题
最近在讨论系统设计时,我突然想到了一个看似荒诞的问题:
"豆子和豆荚,是正交(Orthogonal)的吗?"
在生物学现实中,答案显然是 "否" 。
豆荚(容器)和豆子(内容)是基因层面的共生体。它们共享命运,高度耦合------你种下豌豆的基因,长不出蚕豆的豆荚;豆荚腐烂了,豆子才能落地生根。在物理世界里,它们是"一荣俱荣"的紧耦合关系。
然而,当我们把视线转向软件开发,我们却在拼命追求一种违背生物本能的状态:让"豆荚"和"豆子"完全正交。
这篇文章试图探讨软件设计中的核心追求------正交性(Orthogonality),以及它与我们常说的"解耦"究竟有何区别。
1. 什么是正交性?
"正交"一词源于几何学。如果两条直线互为 90 度夹角,我们称之为正交。
其核心特性是:你在 XXX 轴上的移动,完全不会改变你在 YYY 轴上的坐标。
映射到软件工程中,正交性意味着:
两个或多个事物在发生变化时,互不影响,无副作用。
如果一个系统的设计是正交的:
- 你可以修改 数据库 (Database) 而不需要重写 用户界面 (UI)。
- 你可以改变 业务逻辑 (Business Logic) 而不需要调整 基础设施 (Infrastructure)。
2. 理想的"软件豆荚":泛型与多态
回到开头的比喻。在软件设计中,为了对抗复杂性,我们发明了 List<T>,std::vector<T>,以及各种 Wrapper 类。
- 豆荚(容器): 负责内存管理、扩容、序列化、索引。
- 豆子(内容): 负责业务属性(User, Order, Product)。
在理想的代码世界里,List 根本不应该关心它装的是简单的 Integer 还是复杂的 User 对象。这种**"对内容一无所知" (Agnostic)** 的态度,就是正交性。
由此带来的红利是"组合爆炸"的消除:
- 非正交: 你需要为每种豆子造一个豆荚(
UserList,OrderList...),复杂度是 M×NM \times NM×N。 - 正交: 一个
List<T>可以装载万物,复杂度降低为 M+NM + NM+N。
3. 正交 vs. 解耦:目的与手段
我们在架构讨论中常把"解耦(Decoupling)"挂在嘴边,那么它和"正交"是一回事吗?
我认为它们是一体两面,但维度不同:
| 概念 | 侧重点 | 角色 | 例子 |
|---|---|---|---|
| 解耦 (Decoupling) | 结构 (Structure) | 手段 (Action) | 通过依赖注入 (DI),切断 A 模块对 B 模块的直接引用。 |
| 正交 (Orthogonality) | 行为 (Behavior) | 目的 (Goal) | 因为解耦了,所以当 A 变化时,B 完全不受影响。 |
一句话总结:我们通过"解耦"的手段,试图达成"正交"的效果。
切断依赖
独立演化
手段: 解耦 Decoupling
中间状态: 独立模块
目的: 正交 Orthogonality