【编程哲学 1】从“本质论(继承)”转向“功能论(接口)”

本文主要从哲学的角度来理解UML,方便记忆。

在谈这个话题前,回顾一下UML中泛化(继承)和实现(接口)

 
  • 泛化(继承):本体论 | 实线 ───▷ | 血缘相连(实),指向抽象(▷) | 问:“你从哪里来?”    Dog ───▷ Animal

  • 实现(接口):功能论 | 虚线 - - -▷ | 契约约束(虚),指向抽象(▷) | 问:“你能做什么?”     Repository - -- - -▷ IRepository

一、是什么与能做什么?

(1)是什么

 

哲学问题:

一个事物的本质是什么?即本质先于存在。

在这种思维框架下, 具体事物从第一实体那里继承某些稳定属性,因此可以归类。

例如:狗、猫、─ 鸟───▷动物   

这里:狗 = 动物(一组稳定的属性) + 特殊属性  所以继承表达:个体属于某种更一般的类别。

 泛化(继承)图标的标识 是什么,具体的对象从抽象的对象那里继承稳定属性的,所以用空心的▷,它和具体对象是血脉关联,因此用───实线。

但是现代软件设计发现:如果世界变化很快,“本质”可能不稳定。例如:鸟,企鹅也是鸟,但不会飞,于是继承体系的功能稳定性关系崩溃。 所以现代软件设计用契约关系、功能主义来处理属性继承问题 ,同时减少深层继承。

关键在属性的来源方向——继承的属性是从上往下"继承"来的(纵向、单一谱系、位置固定),接口的属性是可以横向叠加的(一个类可以同时实现 IFlyable、ISwimmable,没有谱系冲突)

继承(接口)关系不是问:你是什么?而是:你具备什么能力?
这是从"本质论"转向"功能论"——而这个转向,在哲学史上有一个更精确的名字:功能主义(functionalism)。

(2)能做什么

哲学上更接近:

萨特的存在决定本质。即存在先于本质,由功能来定义本质,而不是由身份(本质)定义。

普特南(Hilary Putnam)在心灵哲学中提出的功能主义(functionalism)主张:一个状态的本质由它的因果/功能角色定义,而非由承载它的物理基质定义。同一个"疼痛"状态,理论上可以在碳基大脑里实现,也可以在硅基系统里实现——这被称为多重可实现性(multiple realizability)。

这跟接口的核心思想几乎是同一件事:IFlyable 不关心你是鸟、飞机还是超人,只要你实现了 Fly(),你就满足这个契约。软件工程里"面向接口编程"这句话,在哲学上其实早就有专门的学派在讨论了。

实现(接口)图标的标识是"能做什么",是对多个具体对象共同能力关系的抽象,而不是对继承关系本身的抽象。关注对象之间共享的行为契约,如:基于共同契约约束(法律契约、技术标准、协议规范、行业认证、准入协议、文化、道德等),因此用- - - -虚线。

二、更深一层:本质先于存在,还是存在先于本质?

这个对立还可以往哲学史更早的地方推:萨特(Sartre)的存在主义命题——"存在先于本质"(l'existence précède l'essence)。

人没有一个预先设定好的本质,人是通过自己的行动来定义自己的。这几乎可以直接套用在接口思想上:

  • 继承体系更接近本质先于存在:先有 Animal 这个本质范畴,Dog 才被归入其中,身份决定了它能做什么。
  • 接口体系更接近存在先于本质:先有具体的行为承诺(实现了 Fly()),"能飞的东西"这个身份标签是后验贴上去的,行动决定了它是什么。

这也是为什么现代架构中"鸭子类型"(duck typing)、依赖注入这类设计,本质上都是把"你是谁"这个问题往后放,把"你此刻能做什么"放到前面。


 

三、组合优于继承:从实体本体论到关系本体论

继承是纵向的血缘链条,一个对象在这条链条上的位置一旦确定,就很难横向扩展新的身份。而现代架构大量偏好组合优于继承,这背后也有一个哲学对应:怀特海(Whitehead)的过程哲学(process philosophy)反对"实体先于关系"的传统本体论,主张事件与关系才是世界的基本单位,稳定的"实体"只是关系模式暂时凝固下来的样子。

"组合优于继承"正是把"这个对象是什么"的问题,替换成"这个对象和谁发生了关系、持有什么、依赖什么"。血缘关系是纵向的本质传递,位置一旦确定就难以更改;组合关系是横向的拼装,一个类可以同时持有多个能力模块,没有谱系冲突。

四、一个自我拷问:接口的"能力"难道不也是一种属性吗?

如果接口也是"一组稳定的属性"(能飞、能读、能写),那它和继承定义的"属性"到底有什么本质区别?

关键不在于"有没有属性",而在于属性的来源方向:

  • 继承的属性是纵向继承来的——沿着单一谱系向下传递,一个类的位置在树状结构里是固定的,改变谱系代价极高。
  • 接口的属性是横向叠加的——一个类可以同时实现 IFlyable、ISwimmable、IComparable,彼此之间没有位置冲突,也不需要共享祖先。

这也许比"本质论 vs 功能论"这个说法更精确地抓住了两种关系在结构上的根本差异:继承问的是"你在谱系树上的哪个位置",接口问的是"你此刻兑现了哪些契约",而契约是可以任意组合、随时增减的。

五、小结

这也是为什么现代架构大量使用:

图片

 

  • 接口
  • 依赖注入
  • 组合优于继承

因为复杂系统中:

稳定的往往不是对象的身份,而是对象之间形成的契约关系。

posted @ 2026-08-29 14:21  小林野夫  阅读(13)  评论(0)    收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/