在编程教育这个赛道上,Programming with Mosh 是YouTube上最成功的频道之一,主理人Mosh Hamedani是有十余年行业经验的软件工程师,以结构清晰、直击本质的入门课著称。他的一条《Object-Oriented Programming, Simplified》(面向对象,简化讲解)累计播放量已超过489万(截至2026年10月),长期占据"面向对象"关键词搜索的前排位置,被大量计算机课堂和训练营列为课前必看。
这条视频的价值不在"新",而在"准":它把面向对象这个被讲烂了的主题,压缩成四根支柱——封装、抽象、继承、多态,每一根都用最短路径讲清"它到底替你挡住了什么麻烦"。但正因为它讲得太顺,很多观众看完只记住了四个名词,错过了真正重要的一层:这四根支柱里,有两根是坚实的工程共识,有一根在历史上被严重教条化,还有一根从一开始就被发明者本人抱怨"讲歪了"。本文带你把这条视频从头到尾走一遍,再补上它没时间讲的理论源头和它没敢讲的历史争议——看完这篇,你对面向对象的理解会比看完视频多一层。
| 项目 | 内容 |
|---|---|
| 视频标题 | Object-Oriented Programming, Simplified(面向对象编程,简化讲解) |
| 频道 | Programming with Mosh |
| 主讲人 | Mosh Hamedani(软件工程师、在线编程教育者) |
| 发布时间 | 2021年前后(据频道页面) |
| 热度数据 | 播放量489.8万+(截至2026年10月) |
| 链接 | https://www.youtube.com/watch?v=pTB0EiLXUC8 |
视频的开场立论是:程序变复杂的根源,是函数和数据各过各的日子。过程式写法里,一堆全局数据躺在那儿,任何函数都能伸手进来改——改的人多了,谁也说不清某条数据在哪个时刻被谁动过。面向对象的答案朴素得近乎机械:把数据和操作这些数据的函数打包在一起,装进一个"对象"里,从此数据的进出都要走这个对象规定的门。这个开场是全片的地基——后面四根支柱,全部是从"打包"这个动作里长出来的。
第一根支柱是封装(encapsulation)。词源很形象:capsule,胶囊——药粉被壳包着,你只管吞,不用关心里面是化学键怎么接的。视频强调的关键动作是访问控制:把对象内部的状态标记为私有(private),外界只能通过公开的方法读写。于是对象有了一个明确的"门面",内部怎么改,只要门面不变,外面一行代码都不用动。
这一步真正的价值不是"安全",而是收敛了改动的影响半径。没有封装时,一个字段被改坏,你要在全工程里搜谁碰过它;有了封装,嫌疑范围直接缩小到这个类自己的几十行代码。
第二根支柱是抽象(abstraction),也是最容易和封装混淆的一根。视频给出的区分很干脆:封装关心"怎么把细节藏起来",抽象关心"该让用户看到什么"。遥控器上一共就几个按钮,但电视内部是几百万行固件——遥控器设计师做的不是把所有功能摆出来,而是从用户视角倒推,只保留必要的操作。
换句话说,封装是防守动作(藏住不该看的),抽象是设计动作(选出值得看的)。一个类设计得好不好, encapsulation 只是及格线,abstraction 才是分水岭。
第三根支柱继承(inheritance),视频的定位是"消除冗余代码":子类自动获得父类的字段和方法,只需叠加自己的差异。这个讲法本身没错,是教科书标准答案——但它是四根支柱里最需要历史注脚的一根,本文第三节展开。
第四根支柱多态(polymorphism),词面意思是"多种形态"。视频的核心演示是方法重写:父类声明一个方法,不同的子类各自给出自己的实现;调用方只管发出同一条消息,具体谁来应答、怎么应答,由对象自己决定。视频把多态和继承放在一起收尾是有道理的——多态是继承的回报:正因为有父子体系,你才能"面向父类编程",让新增的子类无痛接入现有代码。扩展时加新类,而不是改老代码,这是面向对象许诺给工程师的最大红利。
面向对象的起点通常追溯到挪威计算中心的Ole-Johan Dahl和Kristen Nygaard在1967年发布的Simula 67。他们做的是港口物流和工厂生产的仿真系统,发现不同事物(船、吊车、集装箱)既有各自的属性,又有相似的行为模式,于是发明了 class 和继承,让"一类东西"可以描述成代码。有意思的是,Simula 发明 class 的动机里几乎没有"优雅",全是"省事"——和今天很多人对 OOP 的审美化崇拜正好相反。Dahl 和 Nygaard 因此获得2001年图灵奖(Nygaard 于获奖前夜去世)。
把这套东西推向世界的是Alan Kay。他在1970年代初于施乐帕克研究中心主导设计Smalltalk,也是"object-oriented"这个词的发明人。但 Kay 心中的面向对象,核心是消息传递:程序应该像生物体的细胞,或网络上的计算机——各自封装状态,靠消息协作,任何一个组件都可以被替换。他晚年反复澄清那句著名的抱怨:"我发明了'面向对象'这个词,但C++不是我脑子里的那个东西。"在 Kay 看来,后世把 OOP 等同于"继承+方法重写",恰恰把他最重要的想法(消息传递、组件可替换)丢掉了。2003年,Kay 因 Smalltalk 与图形界面先驱工作获图灵奖。
"藏细节"这件事的理论根基,来自David Parnas 1972年发表的经典论文《On the Criteria To Be Used in Decomposing Systems into Modules》。Parnas 的观点石破天惊:模块划分的依据不应该是流程步骤,而应该是"难以预测的设计决策"——把可能变化的决策藏进模块内部。这就是信息隐藏(information hiding)。注意时间线:Parnas 写这篇论文时面向对象还未流行,他谈的是一切模块化设计的通用原则。今天任何一个语言的封装机制,都是这条原则的工程化落地。看懂这一层你就会明白:封装不是面向对象的专利,而是面向对象把一条更老的智慧变成了语法强制。
继承被滥用之后,第一个出来立规矩的是Barbara Liskov——MIT教授、2008年图灵奖得主。她在1987年OOPSLA大会的主题演讲中提出:所有引用父类的地方,必须能透明地换成子类对象,程序行为不得被破坏——这就是著名的里氏替换原则(Liskov Substitution Principle)。它划出了一条清晰的界线:继承不等于"代码长得像所以继承一下",而是一种严格的类型承诺。正方形能不能继承长方形?数学上能,里氏检验下不能——因为"设置宽度"这个操作在两者上行为不同。1994年出版的《Design Patterns》(Gang of Four 四人帮著)在第一章就写下另一条并立的忠告:"优先使用对象组合而非类继承"。这本书被誉为面向对象设计的圣经,但它最广为引用的观点,其实是给继承泼的冷水。
2000年代初,Robert C. Martin(Uncle Bob)把一批面向对象设计原则整理成SOLID五原则(单一职责、开闭、里氏替换、接口隔离、依赖倒置),成为此后二十年企业级 Java/C# 世界的通用语言。而另一边,质疑声也没停过:Erlang 之父 Joe Armstrong 在《Coders at Work》访谈里留下那句刻薄的名言——"你想要一根香蕉,结果得到的是握着香蕉的大猩猩,外加整片丛林",讽刺深对象树把无关的依赖全部拖进你的代码。Clojure 作者 Rich Hickey 在2011年Strange Loop的《Simple Made Easy》演讲里,把"继承+可变状态+实现继承"列为把简单问题搅复杂的典型手法(他的用词是 complect,缠绕)。这批质疑直接塑造了Go和Rust一代新语言的设计:Go 干脆砍掉继承,用组合加接口;Rust 用 trait 提供多态但拒绝实现继承。
封装与抽象:证据充分,放心吸收。 这两根支柱背后站着 Parnas 的信息隐藏理论和五十多年API设计的工程实践,几乎没有争议。视频把它们排在前面并花大力气区分,是这条视频最有价值的部分。
继承:视频的讲法是合格的简化,但需要补三条警告。 第一,"继承消除重复代码"是危险表述——消除重复的正确工具是提取函数和组合,继承是一种强耦合的类型关系,用它来"省代码"是本末倒置,这正是"香蕉与大猩猩"问题的根源。第二,深继承层次存在脆弱基类问题:父类内部实现的微小调整,可能在毫不知情的子类上引爆——GoF 和《Effective Java》(Joshua Bloch)都专门警告过。第三,多态并不依赖继承才能实现:接口、协议、trait,甚至函数指针都能提供多态;"没有继承就没有多态"是旧教科书留下的错误等式。
"四大支柱"这个框架本身:方便,但不忠于历史。 它是一套教学简化——真实历史里,Kay 的初心是消息传递,Simula 的初心是仿真建模,两者殊途同归到 class,但侧重完全不同。用四支柱理解 OOP 没有问题,把它当成 OOP 的定义就有问题。
另一个方向的夸大也要警惕。 近几年"OOP已死"的论调在技术社区反复出现,这同样是夸张。现实是:面向对象的合理内核(封装边界、接口抽象、多态扩展)已被 Rust 的 trait、Go 的 interface、Swift 的 protocol 吸收,死掉的只是"万物皆继承树"的极端教条。一门六十年的技术被下一代语言拆解吸收,这叫演化,不叫死亡。
第一,审查一个类时,别问"它有什么",问"它藏了什么"。 这是 Parnas 式的检验:一个设计良好的类,应该把至少一个"可能会变的设计决策"关在自己肚子里。如果一个类把所有字段都暴露出去、所有方法都是转手调用的包装,它不是抽象,是废纸——因为它藏不住任何变化,调用方和实现细节已经焊死。
第二,默认组合,继承必须过里氏检验。 每次写下 extends 之前问一句:子类能否在所有场景下透明替换父类?父类将来改内部实现,会不会悄悄破坏子类?两个问题有一个答不上来,就改用组合——把对象作为字段握在手里,比把命脉交给祖先链安全得多。这也是《Effective Java》第18条"组合优先于继承"的原话精神。
第三,用"换实现要改几行"给抽象打分。 好的抽象,替换底层实现(换数据库、换消息队列、换算法)时调用方代码几乎不动;坏的抽象,换一个实现要牵动一串调用方。这条检验把"抽象"从审美问题变成了可测量的工程指标——顺便说,它同样是那个遥控器哲学的自动化版本:遥控器好不好,看换电视时用户要不要重学。
flowchart TD
A["问题:数据与函数各过各的"] --> B["封装:状态藏进胶囊"]
A --> C["抽象:只留必要按钮"]
A --> D["继承:父子复用代码"]
A --> E["多态:一条消息多种应答"]
B --> F["检验:藏住了什么变化"]
C --> F
D --> G["代价:深层树脆弱"]
E --> H["回报:加类不改老代码"]
G --> I["修正:组合优先<br/>里氏替换原则"]
H --> I
本文由「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 等场景全覆盖。
