一、开篇:面向对象设计原则概述
做C++开发这么多年,我经常被问到同一个问题:“代码能跑不就行了?为什么还要搞那么多设计原则?”
说实话,我刚入行那会儿也是这么想的。那时候我觉得,只要程序能编译通过、功能正确,就是好代码。直到有一次,我接手了一个遗留项目——一个庞大的C++单体应用,没有单元测试,类与类之间耦合得像一团乱麻。改一个bug,往往要牵连七八个文件。加一个新功能,得花两周时间梳理依赖关系。
嗯,那次经历让我彻底明白了:代码能跑,和代码好维护,完全是两码事。
设计原则,就是帮你写出“好维护”代码的那套心法。
为什么需要设计原则?
你想想看,软件开发最怕什么?不是需求变更,而是变更带来的连锁反应。今天改了一个基类,明天所有派生类都崩了。今天加了一个新功能,后天发现旧模块的接口全要重写。
设计原则要解决的,就是这些问题:
- 可维护性——改一处,不影响其他地方
- 可扩展性——加新功能,不用改旧代码
- 可复用性——一个模块,能在多个项目里用
- 可测试性——每个类都能单独写单元测试
我在项目中遇到过最典型的反例:一个类干了五件事——网络通信、数据解析、业务逻辑、界面更新、日志记录。结果呢?网络库换了个版本,整个类都得重写。这就是典型的高耦合、低内聚。
核心观点:设计原则不是教条,而是前人踩过的坑总结出来的经验。你遵守它,不是为了“好看”,而是为了以后少加班。
SOLID原则的由来与核心思想
说到面向对象设计原则,绕不开的就是SOLID。这五个字母,代表了五个基本原则:
| 缩写 | 全称 | 中文 | 一句话核心 |
|---|---|---|---|
| S | Single Responsibility Principle | 单一职责原则 | 一个类只做一件事 |
| O | Open/Closed Principle | 开闭原则 | 对扩展开放,对修改关闭 |
| L | Liskov Substitution Principle | 里氏替换原则 | 子类必须能替换父类 |
| I | Interface Segregation Principle | 接口隔离原则 | 接口要小而专,不要大而全 |
| D | Dependency Inversion Principle | 依赖倒置原则 | 依赖抽象,不依赖具体 |
这五个原则,最早是由Robert C. Martin(大家叫他Uncle Bob)在90年代总结出来的。他当时在写一些关于面向对象设计的文章,后来把这些原则整理成了“面向对象设计原则”系列。再后来,有人发现这些原则的首字母拼起来正好是SOLID,这个名字就这么叫开了。
我个人习惯把这五个原则分成两组来理解:
- S + O + L:关注类的职责和继承关系,解决“类该怎么设计”的问题
- I + D:关注接口和依赖关系,解决“类之间该怎么协作”的问题
说白了,SOLID原则就是一套代码设计的“健康检查清单”。你写完代码后,拿这五条逐一对照,看看有没有违反的地方。如果有,大概率以后会出问题。
个人经验:我曾经在一个项目中,因为赶进度,让一个类同时承担了数据存储和业务计算两个职责。结果上线后,业务逻辑改了三次,每次都要动那个类。后来我花了一天时间重构,拆成两个类,之后改业务逻辑再也没碰过存储相关的代码。这就是单一职责原则的价值。
设计原则与设计模式的关系
很多初学者会混淆这两个概念。我简单说一下:
- 设计原则是“道”——是指导思想,告诉你“应该怎么做”
- 设计模式是“术”——是具体方案,告诉你“可以这么做”
举个例子:
开闭原则说:“对扩展开放,对修改关闭。”这是一个原则,但它没有告诉你具体怎么实现。
而策略模式、模板方法模式、装饰器模式,都是实现开闭原则的具体手段。它们提供了可复用的代码结构,让你在加新功能时不用改旧代码。
所以,我的建议是:先理解原则,再学习模式。原则是“为什么”,模式是“怎么做”。你如果只背模式,不知道背后的原则,很容易用错地方。反过来,你理解了原则,很多模式你甚至能自己推导出来。
避坑指南:我曾经见过有人为了用设计模式而用设计模式。一个简单的if-else能解决的问题,硬是套了个工厂模式加策略模式,代码量翻了三倍,可读性反而下降了。记住:设计模式是工具,不是目的。原则才是你真正要遵循的东西。
本章知识体系
下面这张图,帮你理清本章的核心脉络:
这张图把本章的核心内容串了起来。你可以看到:设计原则是中心,它回答了“为什么需要”、“是什么(SOLID)”、“和设计模式什么关系”这三个问题。
接下来的课程,我会逐一深入讲解SOLID的每个原则。每一讲都会结合C++代码示例,分享我在实际项目中的经验和教训。
记住:设计原则不是束缚,而是解放。它让你从“改一处崩一片”的泥潭里解脱出来,让你写的代码经得起时间考验。
公众号:蓝海资料掘金营,微信 deep3321