面向对象编程(OOP)大概是所有编程概念里“背名词率”最高、而“真懂率”最低的一个:封装、抽象、继承、多态,四个词人人会背,问到“为什么继承会出事”却十有八九答不上来。Programming with Mosh(编程教育头部频道主 Mosh Hamedani)的这条《Object-Oriented Programming, Simplified》正是冲着这个问题去的——它不是又一遍念PPT,而是把“四大支柱”还原成一个个具体的痛点和解法。本文以这条488万播放的常青课为底本,逐段拆解它的论证,再补上视频没讲的另一半:这门手艺的历史暗线与工程界的争议面。没看过视频,读完你能掌握它;看过视频,你能比它多懂一层。
选题说明:这不是一条“新片”,而是头部编程教育频道的高热度常青课——对OOP这类基础概念,常青课恰恰是反复被搜索、被新手当作“第一课”的那条视频,拆解它的价值高于追逐一条昙花一现的争论片。
这条视频的叙事结构非常典型:先立“痛”,再逐根立“柱”,最后收“益”。我们按它的叙事顺序拆。
视频没有上来就定义OOP,而是先摆出一个所有初学者都撞过的墙:用过程式思路写程序,数据和操作数据的函数是分离的。小Demo没事,代码一上规模,改一个数据结构,散落各处的函数全要跟着改,牵一发动全身。视频由此引出OOP的第一个承诺:把数据和操作这些数据的行为,打包成一个单位——类(Class)。类是图纸,对象(Object)是按图纸造出来的实例。这一步是全片的地基:后面四根柱子,全部立在这个“打包”之上。
第一根柱子解决“打包之后别让人乱摸”。视频的做法是把字段设为私有(private),只通过公开方法受控访问,典型如银行账户的余额:不允许外部直接改数字,只能走 deposit() 这样的入口,校验逻辑集中在方法里。封装的实质收益视频讲得很清楚:非法状态进不来,修改范围收得住。内部表示想换就换,只要接口不变,调用方一行不用动。
第二根柱子常和封装被混为一谈,视频用了一个区分度很好的类比:电视遥控器。你只需要知道“音量+”是干嘛的,不需要知道红外编码怎么实现。抽象面向的是调用者的心智负担:暴露“做什么”,隐藏“怎么做”。封装是防误用(安全),抽象是降负荷(简单),两者方向不同。
第三根柱子是全片最需要警惕的一段,也是本文后面重点审查的一段。视频以经典的 Person → Student / Teacher 层次演示:把公共字段和方法上提到父类,子类只写差异。到这里为止,演示是干净的——Person和Student确实是"is-a"关系。但视频把继承的首要卖点定位为“消除重复代码”,这个教学取向埋下了初学者日后滥用的种子,批判性审查一节细说。
第四根柱子把前 three 根串起来:把不同子类对象都当成父类类型来对待,循环里一句 obj.render() / obj.calculatePay(),运行时各自找到自己的实现。多态的工程价值在于扩展时的“加法”性质:新增一种形状、一种员工类型,调用方代码不动,只加新类。这其实就是“开闭原则”的雏形,视频没有点破,但逻辑已经到位。
视频结尾把收益归纳为:减少重复、易于维护、便于扩展、团队协作有了共同语言(类名、方法名、类图就是沟通词汇)。作为入门课,这个收束是诚实的;但它只讲了这门手艺的“许诺”,没讲“代价”——这正好是深读要补的部分。
类的概念最早出现在1967年挪威计算中心的 Ole-Johan Dahl 和 Kristen Nygaard 开发的 Simula 67 语言里,仿真建模需要把“一类事物”抽象成可实例化的模板,子类与虚函数也在那时出现。两人因此获得2001年图灵奖。换句话说,OOP出生时的第一动机是建模世界,不是“消除重复”。
把OOP推向大众的是施乐帕克研究中心(Xerox PARC)的 Smalltalk,核心人物 Alan Kay。但今天课堂上的“四大支柱”和 Kay 的原始主张有明显偏差:据其2007年前后在邮件列表中的公开自述以及1997年OOPSLA主题演讲《The Computer Revolution Hasn't Happened Yet》中的反复强调,Kay 认为OOP的要点是消息传递(messaging)、局部保留(encapsulation 的原始含义)、延迟绑定(late binding),并且明确说过“我最近很后悔没有发明‘对象导向’这个词,因为大家都忽略了消息传递这个大 idea”。他后来甚至说过一句常被引用的冷话:我没把 C++ 算作面向对象(据其公开采访)。理解这条暗线,你就明白为什么本文敢说“视频教的是工程共识版OOP,不是创始人的原教旨版”。
Bjarne Stroustrup 在贝尔实验室以"C with Classes"起步,1983年命名为C++,把类塞进了系统级编程;1995年 Sun 的 Java 携“一切皆对象+垃圾回收”横扫企业市场,顺便把“四大支柱”变成了全球教材的标准章节。今天你在视频里看到的 public/private、extends、override 语法,基本都是 Java 系的表述习惯。
1994年,Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides 四人(GoF)出版《设计模式:可复用面向对象软件的基础》,23个模式成为OOP团队的共同语言。值得注意的是,这本书第一章就白纸黑字写了一条原则:优先使用对象组合,而非类继承——"composition over inheritance"不是后人反叛,而是开山之作的原生条款。Robert C. Martin 归纳的 SOLID 五原则(首字母缩写由 Michael Feathers 提出)则把“面向接口、依赖抽象”进一步制度化。
对继承滥用的最有名嘲讽,来自 Erlang 之父 Joe Armstrong:你想要一根香蕉,结果得到的是一只握着香蕉的大猩猩——以及它身后的整片丛林(据其2009年前后的公开演讲与访谈)。代价更低但更具决定性的是两个工业界动作:Google 的 Go 语言(2009年发布,Rob Pike 等)干脆不提供继承,用组合加接口解决问题;.mozilla/系统级的 Rust 走 trait 路线,同样绕开传统类继承。两大新语言用脚投票,说明“继承是复用第一工具”这个教学取向,在工程界已经松动。视频作为入门课没有覆盖这层——不怪它,但读者必须知道。
立得住的部分。 四大支柱在C++/Java/C#系语言里是几十年沉淀的工程共识:封装集中校验、防止非法状态;抽象隔离变化、降低调用方心智负担;多态支持“加法式扩展”。这些不是理论玄学,任何读过一个中型真实代码库的人都能在代码里找到对应物。视频的演示本身也干净克制,没有教坏人的例子。
要打折扣的部分,主要三处。
第一,“OOP让代码更易维护”是条件命题,不是充分条件。继承用过了头——层级过深、子类依赖父类实现细节——就是经典的“脆弱基类问题”(fragile base class):父类一个看似无害的内部修改,会在不相关的子类上炸出 bug。视频以“消除重复”作为继承的头号卖点,对初学者是一个危险的引导方向:为复用而继承恰恰是烂层次结构的第一成因。复用请优先用组合,继承只留给真正的 is-a 语义和多态需要——这才是 GoF 原文和现代语言实践的共识。
第二,视频演示 getter/setter 式封装时,若被初学者机械套用,会产生“每个字段一对 get/set”的退化写法。这种代码只是把字段换了个名字访问,封装名存实亡——对象退化成“带方法的裸数据结构”。Java 社区早年对此有过激烈批评(如 Allen Holub 在 JavaWorld 发表的《Why getter and setter methods are evil》,2003)。正确的封装问的不是“怎么取到数据”,而是“这个对象该负什么责任”。
第三,“四大支柱”不等于OOP的全部,更不等于唯一正解。Kay 一再强调消息传递才是核心;函数式路线质疑可变状态的封装,主张不可变数据;Go 与 Rust 则干脆修改了游戏规则。视频作为入门课立场中立地教“主流Java版OOP”没有错,但观众应该知道:你学到的是一种方言,不是OOP这门语言本身。
一句话总结:这条视频对“是什么、怎么用”讲得扎实可靠,对“什么时候不该用”几乎留白——入门课的普遍短板,也是本文存在的理由。
1. 先学模型,再背命令。 用十分钟亲手“解剖”一次:随便找一个你项目里的类,回答两个问题——它负责哪些数据?谁在调用它的方法?如果它的字段全靠 getter/setter 裸奔、方法只是外挂工具,那它就不是对象,是结构体。这一问一答,比看十遍定义更能建立封装的手感。
2. 给继承装一道闸门:三问清单。 写下 extends 之前自问:这真是 is-a 关系吗?父类未来会怎么变,我的子类承受得住吗?我的子类会用到父类的全部行为吗?任何一问答“否”,改用组合。把这条清单放进你的代码评审习惯,一两周就能看到层次结构变干净。
3. 把OOP当词汇表,别当信仰。 从GoF的23个模式里挑两三个最常用的(策略、观察者、装饰器),对照一段你读得懂的真实开源代码看它们如何用多态“变现”。目标是获得工程词汇和判断力,而不是集邮式背完23个模式——模式的滥用和继承的滥用,是同一枚硬币的两面。
flowchart TD
A["过程式的痛<br/>数据与操作分离"] --> B["类与对象<br/>数据和行为打包"]
B --> C["封装<br/>私有字段受控访问"]
B --> D["抽象<br/>只暴露必要接口"]
C --> E["继承<br/>is-a关系复用"]
D --> F["多态<br/>同一接口多种实现"]
E --> G["四大支柱的承诺<br/>少重复 易维护"]
F --> G
G --> H["现实的岔路<br/>深层继承=脆弱基类"]
H --> I["工程共识<br/>组合优于继承"]
H --> J["范式之争<br/>Go与Rust的取舍"]
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
