阿里P7架构师石锤:类与数据结构的比较!每个优秀的软件设计师和架构师都需要牢记的问题

什么是类

  • 类是一组类似对象的规范。

什么是对象

  • 对象是一组对封装数据元素进行操作的函数。
  • 或者更确切地说,对象是一组对隐含数据元素进行操作的函数。

暗示数据元素是什么意思

  • 对象的功能意味着存在一些数据元素; 但是该数据不能直接在对象外部访问或可见。

是不是对象里面的数据

  • 它可能是; 但是没有规则说必须这样。从用户的角度来看,对象只不过是一组功能函数。这些函数操作的目标数据必须存在,但用户不知道该数据的位置。

好,什么是数据结构

  • 数据结构是一组有凝聚力的数据元素。
  • 或者,换句话说,数据结构是由隐含函数操作的一组数据元素。

好的好的。我知道了。对数据结构进行操作的函数不是由数据结构指定的,但数据结构的存在意味着某些操作必须存在

  • 对,那么你对这两个定义有什么看法?

类和数据结构彼此相反

  • 确实。它们是彼此的补充。它们像手套一样装在一起。
  • 对象是一组对隐含数据元素进行操作的函数。
  • 数据结构是由隐含函数操作的一组数据元素

哇,所以对象不是数据结构

  • 正确。对象与数据结构相反。

那么DTO - 数据传输对象 - 不是一个对象

  • 正确!DTO是数据结构。

所以数据库表也不是对象吗

  • 再次纠正。数据库包含数据结构,而不是对象。

可是等等。ORM 对象关系映射器是不是将数据库表映射到对象

  • 当然不是。数据库表和对象之间没有映射。数据库表是数据结构,而不是对象。

那么ORM做什么呢

  • 它们在数据结构之间传输数据。

所以他们与对象没有任何关系

  • 没什么。没有对象关系映射器这样的东西; 因为数据库表和对象之间本身就无法映射。

但我认为ORM为我们构建了业务对象

  • 不,ORM提取业务对象操作的数据。该数据包含在ORM加载的数据结构中。

但那么业务对象不包含该数据结构吗

  • 它可能。它可能不会。这不是ORM的业务。

这似乎是一个小的语义点

  • 一点也不。这种区别具有重要意义。

比如

  • 例如数据库模式的设计与业务对象的设计。业务对象是定义业务行为的结构。 数据库模式是定义业务数据的结构。这两种结构受到非常不同的力量的约束。业务数据的结构不一定是业务行为的最佳结构。

嗯。这令人困惑

  • 这样想吧。数据库架构不针对一个应用程序进行调整; 它必须服务于整个企业。因此,该数据的结构是许多不同应用程序之间的折衷。

好的,我明白了

  • 好。但现在看看每个单独的应用。每个应用程序的对象模型描述了这些应用的行为结构的方式。每个应用程序都有一个不同的对象模型,微调该应用程序的一些行为。

原来如此。由于数据库模式是所有各种应用程序的折衷,因此该模式将不符合任何特定应用程序的对象模型

  • 对!对象和数据结构受到非常不同的力量的约束。他们很少很好地协调在一起工作。人们习惯称之为对象/关系阻抗不匹配。

我听说过这个。但我认为阻抗不匹配是由ORM解决的

  • 现在你的想法现在不同了。没有阻抗不匹配,因为对象和数据结构是互补的,而不是同构的。

什么

  • 它们是对立的,而不是类似的实体。

对立

  • 是的,以一种非常有趣的方式。你看,对象和数据结构意味着截然相反的控制结构。

等等,什么

  • 想想一组所有符合公共接口的对象类。例如,想象一下表示二维形状的类,它们都具有计算形状area和perimeter形状的功能。

为什么每个软件示例总是涉及形状

  • 我们只考虑两种不同的类型:Squares和Circles。应该清楚的是,这两个类的area和permimeter函数在不同的隐含数据结构上运行。还应该清楚,调用这些操作的方式是通过动态多态。

等待。慢一点。什么

  • 有两种不同的area函数; 一个用于Square,另一个用于Circle。当调用者调用area特定对象上的函数时,该对象知道要调用的函数。我们称之为动态多态。

好。当然。该对象知道其方法的实现。当然

  • 现在让我们将这些对象转换为数据结构。我们将使用Discriminated Unions。

Discoominated什么

  • 可区分联合discriminated unions。在我们的例子中,这只是两种不同的数据结构。一个为Square,另一个为Circle。该Circle数据结构具有一个中心点,和用于数据元素的半径。它还有一个类型代码,可以将其标识为Circle。

你的意思是像一个枚举

  • 当然。该Square数据结构具有左上点,并且侧的长度。它还有类型鉴别器 - 枚举。

好。两个带有类型代码的数据结构

  • 对。现在考虑这个area功能。它会有一个switch语句,不是吗?

嗯。当然,对于两种不同的情况。一个为Square另一个为Circle。并且该perimeter函数将需要类似的switch语句

  • 再一次。现在考虑这两种情景的结构。在对象场景中,area函数的两个实现彼此独立并且属于(在某种意义上的单词)各自类型。 Square的area函数属于Square,Circle的area函数属于Circle。

好的,我知道你要去哪里。在数据结构场景中,area函数的两个实现在同一个函数中,它们不属于“类型”(但是你的意思是那个词)

  • 它变得更好了。如果要将Triangle类型添加到对象方案中,必须更改哪些代码?

没有代码更改。您只需创建新Triangle类。哦,我想这个实例的创建者必须改变

  • 对。因此,当您添加新类型时,几乎没有变化。现在假设您要添加一个新函数 - 比如center函数。

那么,你就必须将它添加到所有三种类型,Circle,Square,和Triangle

  • 好!因此类添加新函数很难,您必须更改每个类。

但是对于数据结构,它是不同的。为了添加新Triangle新类型,您必须更改每个函数以将Triangle匹配情况添加到switch语句中

  • 对!数据结构添加新类型很难,您必须更改每个函数。

但是当你添加新center函数时,数据结构不需要任何改变

  • 对!数据结构添加新函数很容易。

哇。两者恰恰相反

  • 绝对是相反:
  • 向一组类添加新函数很难,您必须更改每个类;将新函数添加到一组数据结构很容易,只需添加函数,不做任何其他更改。
  • 将新类型添加到一组类很简单,只需添加新类即可;向一组数据结构添加新类型很难,您必须更改每个函数。

是啊。对立统一。以有趣的方式对立。我的意思是,如果您知道要将新函数添加到一组类型中,那么您需要使用数据结构。但是如果你知道你将要添加新类型,那么你想要使用类

  • 好!但今天我们还有最后一件事要考虑。还有另一种方式,数据结构和类是对立的。它与依赖关系有关。

依赖

  • 是的,源代码依赖的方向。

好的,我会咬人的。有什么不同

  • 考虑数据结构案例。每个函数都有一个switch语句,它根据区分联合中的类型代码选择适当的实现。

好的,那是真的。但那又怎么样

  • 考虑调用area函数。调用者依赖于area函数,area函数取决于每个特定的实现。

“依赖”是什么意思

  • 想象一下,如果每个类实现area函数,都有写入了它自己的函数。因此,有circleArea和squareArea和triangleArea单独自己的实现area函数。

好的,所以switch语句只调用那些函数

  • 想象一下,这些函数放在不同的源文件中。

然后,带有switch语句的源文件必须导入、使用或包含所有这些源文件

  • 对。这是源代码依赖。一个源文件依赖于另一个源文件。这种依赖的方向是什么?

带有switch语句的源文件取决于包含所有实现的源文件

  • 那个area函数的调用者怎么样?

area函数的调用者依赖于具有switch语句的源文件,该语句取决于所有实现

  • 正确。所有源文件依赖关系都指向调用方向,从调用者到实现。因此,如果您对其中一个实现进行微小更改......

好的,我知道你要去哪里。对任何一个实现的更改都将导致重新编译带有switch语句的源文件,这将导致调用该switch语句的每个人area(我们的情况下的函数)被重新编译

  • 对。至少对于依赖于源文件的日期来确定应该编译哪些模块的语言系统来说是这样的。

几乎所有这些都使用静态类型,对吧

  • 是的,有些则没有。

很多重新编译

  • 还有很多重新部署。

好的,但是在类的情况下这是相反的吗

  • 是的,因为area函数的调用者依赖于接口,并且实现函数也依赖于该接口。

我明白你的意思了。类的源文件Square导入或使用或包含Shape接口的源文件

  • 对。实现的源文件指向调用的相反方向。他们从实现指向调用者。对于静态类型语言至少也是如此。对于动态类型语言,area函数的调用者完全不依赖于任何东西。链接在运行时得到解决。

对。好。因此,如果您对其中一个实施进行了更改......

  • 只需重新编译或重新部署已更改的文件。

这是因为源文件之间的依赖关系指向调用的方向

对。我们称之为依赖倒置。

总结

好的,那么让我看看我是否可以把它合起来。类和数据结构至少以三种不同的方式存在。

  1. 类在保持数据隐含的同时使函数可见。数据结构使数据可见,同时保持隐含的函数
  2. 类使添加类型变得容易,但很难添加函数。数据结构使添加函数变得容易,但很难添加类型
  3. 数据结构将调用者公开给重新编译和重新部署。类将调用者与重新编译和重新部署隔离开来

你说对了,这些是每个优秀的软件设计师和架构师都需要牢记的问题。

写在最后

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260