面向对象不是一个语法特性,是三样东西叠在一起:编程技术、设计技术、工程方法;把它们捆在一个词里,正是它让人犯迷糊的地方。
全书开篇。这一节先把全景摊开,后面十一章都是在这张图上落位。
一、三个问题,三套答案
软件开发一直在被三个问题追着跑:代码怎么组织、软件怎么拆、人怎么协作。 面向对象给了三套答案,而它们恰好共用一个名字: 编程技术——类、封装、多态、继承。解决【代码怎么放】。 设计技术——职责分配、UML、建模。解决【软件怎么拆】。 工程方法——框架、设计模式、敏捷开发。解决【团队怎么干】。 这三层不是并列的,是叠起来的:下面一层解决不了的问题,才催生上面一层。
二、一个例子看清第一层价值
需求:一组图形,要算面积、算周长、报出名字。现在要加一种新图形。
过程式写法是三个函数,每个函数里一条 if 链——加一种形状要动三处,漏一处就是 bug。
对象式写法是每个图形一个类,各自带三个方法——加一种形状只要新写一个类,已有代码零改动。
这就是第一层价值:把【改哪里】从【到处找】变成【加一块】。
三、为什么非要把它们捆在一个词里
因为这三层是同一个目标的三段路:让软件好改。 只有类语法、没有设计——类的数量会失控,比过程式更难改。 只有设计、没有工程方法——需求一变,设计全废。 所以说它综合,不是修辞。拆开看,任何一层单独拿出来都不够用。
四、这一课怎么读
读完每一节,问自己一句:这一节站在哪一层说话? 第 4、5 章在语言与内存层,第 8~10 章在设计层,第 6、7、11 章在重用与工程层。 分不清层次,就会拿语言层的定义去套设计层的争论,越读越糊涂——这正是 1.7 要讲的。
五、动手 Demo:面向对象是软件开发的综合技术
先把三层摊开,再用一个【加形状】的例子看清第一层的价值。 下面两段代码都是能跑的,数一数加一种形状要改几处。
proc_code = [
"def area_proc(kind, a, b):",
" if kind == 'rect': return a * b",
" elif kind == 'circle': return 3.14159 * a * a",
"def perim_proc(kind, a, b):",
" if kind == 'rect': return 2 * (a + b)",
" elif kind == 'circle': return 2 * 3.14159 * a",
"def name_proc(kind):",
" if kind == 'rect': return '矩形'",
" elif kind == 'circle': return '圆'",
]
n_func = sum(1 for s in proc_code if s.strip().startswith("def "))
n_chain = sum(1 for s in proc_code if "if kind ==" in s)
print("函数", n_func, "条 if 链", n_chain)
# 对象式:新增形状只加一个类,不改已有代码
class Rect:
def __init__(self, a, b): self.a, self.b = a, b
def area(self): return self.a * self.b
def perim(self): return 2 * (self.a + self.b)
def name(self): return "矩形"
print("新增形状要动的已有代码", 0, "处")
实跑输出:
--------------------------------------------------------------------
面向对象是软件开发的综合技术
--------------------------------------------------------------------
这一章先把全景摊开:**面向对象不是一门语法,是三样东西叠在一起。**
层次 它解决的问题 本书在哪讲
-------------------------------------------------------------------
编程技术 代码怎么组织:类、封装、多态、继承 第 4、5 章
设计技术 软件怎么拆:职责分配、UML、建模 第 8、9、10 章
工程方法 团队怎么协作:框架、模式、敏捷 第 6、7、11 章
为什么非要把它们捆在一个词里?**看一个具体场景就明白。**
需求:一组图形,要算面积、算周长、报出名字。现在要加一种新图形。
过程式写法——三个函数,每个函数里一条 if 链:
def area_proc(kind, a, b):
if kind == "rect": return a * b
elif kind == "circle": return 3.14159 * a * a
def perim_proc(kind, a, b):
if kind == "rect": return 2 * (a + b)
elif kind == "circle": return 2 * 3.14159 * a
def name_proc(kind):
if kind == "rect": return "矩形"
elif kind == "circle": return "圆"
数一数这份代码:**3 个函数,6 条 if 链。**
加【三角形】= **6 处都要动**,漏一处就是 bug。
对象式写法——每个图形一个类,各自带三个方法:
class Rect:
def __init__(self, a, b): self.a, self.b = a, b
def area(self): return self.a * self.b
def perim(self): return 2 * (self.a + self.b)
def name(self): return "矩形"
class Circle:
def __init__(self, r): self.r = r
def area(self): return 3.14159 * self.r * self.r
def perim(self): return 2 * 3.14159 * self.r
def name(self): return "圆"
加【三角形】= **新写一个类,已有代码 0 处改动。**
过程式 对象式
---------------------------------------------------------
新增形状要动的已有代码 6 处 0 处
代码放在哪 同一批函数里 新文件即可
谁来改 最熟悉这段的人 谁加谁改
**这就是面向对象的第一层价值:把【改哪里】从【到处找】变成【加一块】。**
而这件事要成立,光有 `class` 语法不够——还得有设计(怎么拆)、
有工程方法(谁负责哪块)。**所以说它是综合技术,不是修辞。**
实测:3 个函数、3 条 if 链——加【三角形】要动三处。 对象式那边零改动,只新写一个类。这就是【改哪里】从【到处找】变成【加一块】。
30 秒实验
- 找一段自己写过的长
if/elif,试着把它拆成几个类,看看调用方要不要改。 - 想一想:如果团队里十个人同时加形状,两种写法分别会发生什么。
常见误区
- 把面向对象当成【会写 class 就行】。那只是第一层。
- 以为三层是并列的知识点。它们是叠起来的,下面解决不了才长上面。
自测三问(点开对答案)
1. 面向对象这个综合技术包含哪三层? —— 编程技术(类、封装、多态、继承)、设计技术(职责分配、UML、建模)、工程方法(框架、模式、敏捷)。 2. 为什么加一种形状时,对象式写法不用改已有代码? —— 因为每个图形自带自己的三个方法,新增形状只是新增一个类,原有的类一个字都不用动。 3. 为什么说【综合】不是修辞? —— 因为三层是同一个目标的三段路:只有语法会失控,只有设计会随需求报废,拆开任何一层都不够用。- ☐ 下一节(1.2 以对象为中心编写软件的开发方法)
相关笔记
- 本书的构成 — 这张全景图对应哪几章
- 原因之三:面向对象的概念是抽象的 — 【分层】这件事为什么难
- ⌨️ 编程原理 · 索引 — 编程全貌课
- ⚙️ 程序是怎样跑起来的(第3版) · 索引 — 同一系列的机制课
- 🧩 面向对象是怎样工作的 · 索引