it-swarm.cn

什么是抽象?

对于程序员所使用的编程抽象,是否存在公认的定义? [注意,不要将编程抽象与单词“ abstraction”的字典定义混淆。]是否存在明确的甚至是数学的定义?有哪些清晰的抽象示例?

38
mlvljr

答案是“您可以在数学上定义或多或少定义什么是编程抽象吗?”没有。”抽象不是数学概念。这就像要求某人用数学解释柠檬的颜色。

但是,如果您想要一个好的定义:抽象是从特定思想转变为更笼统的思想的过程。例如,看一下鼠标。无线吗?它有什么样的传感器?多少个按钮?符合人体工程学吗?它有多大?所有这些问题的答案都可以准确地描述您的鼠标,但是无论答案是什么,它仍然是鼠标,因为它是带有按钮的定点设备。这就是鼠标的全部条件。 “ Silver Logitech MX518”是一个具体的特定项目,而“鼠标”是该项目的抽象。要考虑的一个重要问题是,没有像“鼠标”这样的具体对象,它只是一个想法。桌子上的鼠标总是更具体-它是Apple魔术鼠标,Dell光电鼠标或Microsoft IntelliMouse-“鼠标”只是一个抽象概念。

您可以根据需要分层抽象和任意细粒度(MX518是鼠标,它是指向对象,它是计算机外围设备,是由电力驱动的对象),可以随心所欲,并且几乎在任何方向上都可以使用(我的鼠标带有导线,这意味着我可以将其归类为带有导线的对象。它也平放在底部,因此我可以将其归类为一种在滚动时不会滚动的对象垂直放置在倾斜的平面上)。

面向对象的程序设计建立在抽象,抽象或抽象的概念上。好的OOP意味着在适当的细节级别上选择良好的抽象,这些抽象在您的程序域中有意义,并且不会“泄漏”。前者意味着将鼠标分类为可以赢得胜利的对象“在倾斜的平面上滚动对于库存计算机设备的应用程序没有意义,但对物理模拟器来说可能是有意义的。后者意味着您应避免将自己“塞进”一个没有层次结构的层次结构中。例如,在上面的层次结构中,我们确定all个计算机外围设备都由电源供电吗?手写笔?如果要将手写笔归为“外围设备”类别,则会遇到问题,因为它不使用电能,因此我们将计算机外围设备定义为使用电能的对象。 圆椭圆问题 是这个难题最著名的例子。

46
nlawalker

我完全不同意大多数答案。

这是我的答案:

给定两个集合G和H,可以在它们之间定义Galois连接(alpha,beta),并且可以说一个是另一个的具体化。反向连接,一个是另一个的抽象。这些函数是具体化函数和抽象函数。

这是基于计算机程序抽象解释的理论,该理论通常是迄今为止的静态分析方法。

25
Paul Nathan

抽象更多地关注What,而更少关注How。或者您可以说,只知道您需要做的事情,并且仅信任提供者提供的所有其他服务。有时甚至会隐藏服务提供商的身份。

例如,此站点提供了一个用于提问和回答的系统。这里几乎每个人都知道本网站进行询问,回答,投票和其他操作的程序。但是很少有人知道什么是底层技术。就像该站点是使用ASP.net mvc还是Python开发的,它都可以在Windows或Linux服务器等上运行。因为这与我们无关。因此,该站点在其底层机制上为我们提供服务保留了一个抽象层。

其他一些例子:

  • 汽车隐藏了所有机械装置,但提供了一种驱动,加油并将其维护的方法。

  • 任何API都会隐藏其所有实现细节,从而向其他程序员提供服务。

  • OOP)中的类隐藏其私有成员,并提供提供调用公共成员的服务的公共成员的实现。

  • 使用Interfaceabstract class in Java或C++,真正的实现是隐藏的。不仅是隐藏的,在Interface中声明的方法的实现在各种实现中也可能有所不同/继承的类,但是当您获得相同的服务时,不必理会How的实现,而恰好Who/What提供了服务。

  • 身份隐藏:对于句子“我知道山姆可以编写计算机程序”。抽象可以是“ Sam是一名程序员。程序员知道如何编写计算机程序。”在第二句话中,人并不重要。但是他的编程能力很重要。

13
Gulshan

编程抽象是问题的简化模型

例如,TCP/IP连接是对发送数据的抽象。您只需提供一个IP地址和一个端口号,然后将其发送给API。您不必担心接线,信号,消息格式和故障的所有详细信息。

7
C. Ross

抽象只是定理的编程版本。

您有一个正式的系统,并提出了关于该系统的想法。您对此进行证明,如果可以解决,那么您就有一个定理。知道您的定理成立后,您便可以将其用于有关系统的进一步证明。系统提供的基元(例如if语句和int值类型)通常被视为公理,尽管严格来说并非如此,因为不是用计算机代码编写的CPU指令的任何事物都是一种抽象。

在函数式程序设计中,将程序作为数学语句的想法非常强烈,并且通常可以使用类型系统(以诸如Haskell,F#或OCAML之类的强大的静态类型语言)通过证明来测试定理。

例如:假设我们将加法和相等检查作为原始操作,将整数和布尔值作为原始数据类型。这些是我们的公理。所以我们可以说1 + 3 == 2 + 2是一个定理,然后使用加法,整数和等式的规则看这是否是对的陈述。

现在让我们假设我们想要乘法,并且我们的原语(为简便起见)包括循环构造和分配符号引用的方法。我们可以建议

ref x (*) y := loop y times {x +}) 0

我要假装证明了这一点,证明了乘法是成立的。现在,我可以使用乘法对系统(编程语言)进行更多处理。

我还可以检查我的类型系统。 (*)的类型为int-> int-> int。它需要2个整数并输出一个整数。加法的类型为int-> int-> int,因此只要(rest)产生一个int,0 +(rest)成立。我的循环可能会做各种各样的事情,但是我说的是它输出了一系列咖喱函数,结果是(x +(x +(x ... + 0)))。该加法链的形式是(int->(int->(int ...-> int))),所以我知道我的最终输出将是一个int。因此,我的类型系统保留了我其他证明的结果!

多年来,许多程序员和许多代码行使这种想法变得复杂,您拥有了现代的编程语言:丰富的原语集和庞大的“经过验证的”代码抽象库。

7
CodexArcanum

您在这里得到了很好的答案。我只警告您-人们认为抽象某种程度上是需要放在基座上的奇妙事物,而您可能做不到。它不是。这只是常识。它只是识别事物之间的相似性,因此您可以将问题解决方案应用于一系列问题。

请允许我一个...

在我的烦恼清单中,最重要的是人们谈论“抽象层”时,好像这是一件好事。他们围绕他们不喜欢的类或例程创建“包装器”,并将它们称为“更抽象的”,似乎会使它们变得更好。还记得《公主与豌豆》的寓言吗?公主是如此的娇柔,以至于如果她的床垫下面有豌豆,她将无法入睡,而增加更多的床垫也无济于事。增加更多“抽象”层会有所帮助的想法就是这样-通常不会。这仅意味着对基本实体的任何更改都必须通过多层代码来体现。

4
Mike Dunlavey

我想您可能会发现 我的博客文章 关于泄漏抽象很有用。相关背景如下:

Abstraction是一种机制,可以帮助理解一组相关程序片段之间的共同点,消除它们之间的差异,并使程序员能够直接使用表示这个抽象的概念。这个新的构造(实际上)总是具有参数化:一种自定义构造构造以适应您的特定需求的方法。

例如,List类可以抽象出链表实现的详细信息-在这里,您可以思考而不是操纵nextprevious指针在向序列添加或删除值的级别上。 抽象是从少量更原始的概念中创建有用,丰富且有时复杂的功能的基本工具。

抽象与封装和模块化有关,而这些概念经常被误解。

List示例中,可以使用encapsulation来隐藏链接列表的实现细节。例如,在面向对象的语言中,您可以将nextprevious指针设为私有,仅允许List实现访问这些字段。

封装不足以进行抽象,因为它不一定意味着您对结构有新的或不同的概念。如果所有List类都给了您'getNext'/'setNext'样式访问器方法,它将从实现细节中封装您(例如,您是否命名字段'prev'或'previous'?它的静态类型是什么?),但是抽象度很低。

模块化信息隐藏:在接口中指定了稳定的属性,然后一个模块实现该接口,并将所有实现细节保留在该模块内。模块化有助于程序员应对变化,因为其他模块仅依赖于稳定的接口。

封装可以帮助信息隐藏(这样您的代码就不必依赖不稳定的实现细节了),但是对于模块化而言,封装不是必需的。例如,您可以在C中实现List结构,向世界公开'next'和'prev'指针,但还提供一个包含initList()addToList()removeFromList()函数。只要遵守接口的规则,就可以保证某些属性将始终保持不变,例如确保数据结构始终处于有效状态。 [例如,Parnas关于模块化的经典论文是用Assembly中的一个示例编写的。该接口是合同和设计的一种交流形式,尽管我们今天依靠它,但不一定必须对其进行机械检查。]

尽管将抽象,模块化和封装之类的术语用作正面的设计描述,但重要的是要意识到,存在以下任何一种特性并不能自动为您提供良好的设计:

  • 如果n ^ 3算法被“很好地封装”,它的性能仍然会比改进的n log n算法差。

  • 如果某个接口适用于特定的操作系统,那么,例如,当需要将视频游戏从Windows移植到iPad时,模块化设计的优势将无法实现。

  • 如果创建的抽象暴露了太多无关紧要的细节,那么它将无法使用其自身的操作来创建新的构造:它只是同一事物的另一个名称。

4
Macneil

维基百科的答案足够好吗? http://zh.wikipedia.org/wiki/Abstraction_%28programming%29

在计算机科学中,抽象的机制和实践减少并分解了细节,以便人们一次可以专注于几个概念。

4
John Fisher

从数学上来说,“整数”是一个抽象。而且,当您对所有整数进行形式为x + y = y + x的形式证明时,您正在使用抽象“整数”而不是特定的数字(例如3或4)。在与机器位于寄存器和存储器位置之上的级别。在大多数情况下,您可以在更抽象的层次上思考更强大的思想。

4
Kate Gregory

作为向其他人解释的一种方式,我会从结果返回相反的方向:

计算机编程中的抽象是将某事物概括为某种程度的行为,即通常可以将多个相似的事物视为相同并进行相同的处理。

如果您想扩展它,可以添加:

有时这样做是为了实现多态行为(接口和继承),从而减少了重复代码,而有时这样做是为了将来可以用类似的解决方案替换某些东西的内部工作而不必更改代码在抽象的容器或包装的另一侧,希望将来减少返工。

除此之外,我认为您必须开始举例说明...

2
Bill

抽象是指当您忽略被认为无关的细节而赞成被认为相关的细节时。

抽象包括封装,信息隐藏和概括。它不包含类推,隐喻或启发式方法。

任何用于抽象概念的数学形式主义本身都会成为抽象,因为它必然要求将基础事物抽象为一组数学属性! 态射 的类别理论概念可能最接近您要寻找的概念。

抽象不是您声明的东西,而是您的事情。

2
Steven A. Lowe

好的,我想我已经知道您要问的问题:“什么是'抽象'的严格数学定义。”

如果是这样,我认为您不走运-“抽象”是软件体系结构/设计术语,据我所知没有数学上的支持(也许某个精通理论CS的人会纠正我)这里),除了“耦合”或“信息隐藏”以外,还有数学定义。

2
Fishtoaster

我一直认为编程中的抽象是隐藏细节并提供简化的界面。这是程序员可以将艰巨的任务分解为可管理的部分的主要原因。使用抽象,您可以为部分问题创建解决方案,包括所有详细的细节,然后提供一个简单的界面来使用该解决方案。然后,您实际上可以“忘记”详细信息。这很重要,因为一个人无法立即将一个超级复杂系统的所有细节都牢记在心。这并不是说抽象底层的细节永远都不需要重新讨论,而是暂时只记住接口。

在编程中,此简化接口可以是从变量(抽象一组位并提供更简单的数学接口)到函数(抽象处理量到单个行调用中)到类以及其他任何东西。

最后,程序员的主要工作是通常将所有计算细节抽象出来,并提供一个简单的界面(如GUI),一个对计算机工作原理一无所知的人可以利用。

抽象的一些优点是:

  • 允许将大问题分解为可管理的部分。当将一个人的记录添加到数据库中时,您并不需要在数据库上插入和平衡索引树而感到困惑。这项工作可能在某个时候已经完成,但是现在已经被抽象化了,您不必再为它担心。

  • 允许多个人一起完成一个项目。我不想知道我同事代码的所有内容。我只想知道如何使用它,做什么以及如何将其与我的作品(界面)配合使用。

  • 允许没有必要知识的人执行复杂的任务。我妈妈可以更新她的Facebook,她在全国各地认识的人都可以看到它。没有一个疯狂的复杂系统到一个简单的Web界面的抽象,她就不可能开始做类似的事情(我也不会这样做)。

但是,抽象可能会产生相反的效果,如果过度使用抽象,它会使事情变得难以管理。通过将问题分解为太多小片段,您必须记住的接口数量会增加,并且很难理解真正的情况。像大多数事物一样,必须找到平衡点。

1
Jason B

我尝试向人们描述它的一种方法,可能不是最好的方法

考虑一个加2 + 2并输出4的程序

考虑一个程序,该程序将用户输入的两个数字相加,x + y = z

哪个更有用和更通用?

1
Bryan Harrington

我认为抽象是隐藏不必要细节的东西。过程是最基本的抽象单元之一。例如,当我从文件中读取数据时,我不想担心如何将数据保存到数据库中。因此,我创建了一个save_to_database函数。

抽象也可以结合在一起以形成更大的抽象。例如,功能可以放在一个类中,类可以放在一个程序中,程序可以放在一个分布式系统中,等等。

1
Jason Baker

这实际上是我想写博客的时间更长的时间,但是我从来没有去过。幸运的是,我是代表僵尸,甚至还有赏金。 我的帖子原来很长 ,但这是本质:

编程中的抽象是关于在给定上下文中理解对象的本质的。

[...]

抽象不仅被误认为是泛化,而且还被封装所误解,但它们是信息隐藏的两个正交部分:服务模块决定其愿意展示的内容,客户端模块决定其愿意看到的内容。封装是第一部分,而抽象则是后者。只有两者一起构成完整的信息隐藏。

希望能有所帮助。

1
back2dos

间接的额外级别。

您不需要关心所使用的对象是Cat还是Dog,因此您可以通过虚函数表查找正确的makeNoise()功能。

我确信这也可以应用于“较低”和“较高”级别-想一想编译器查找正确指令以用于给定处理器,或者通过调用所有内容来对计算效果进行抽象的Haskell Monads抽象return>>=

1
yatima2975

您可能要查看Bob Martin的一些指标

http://zh.wikipedia.org/wiki/Software_package_metrics

就是说,我认为他的“抽象性”与您的不同。他的用法更多地是“缺乏对类的实现”的一种度量,意味着使用接口/抽象类。与主序列的不稳定性和距离可能会在您要寻找的内容中发挥更大的作用。

1
MIA

抽象是用其他东西来表示某些东西(例如概念,数据结构,函数)。例如,我们使用文字进行交流。单词是一个抽象实体,可以用声音(语音)或图形符号(书写)表示。抽象的关键思想是所讨论的实体与基础表示形式有所不同,就像单词不是用来说出它的声音还是用来写出它的字母一样。

因此,至少在理论上,抽象的基础表示可以用其他表示代替。但是,实际上,抽象很少与底层表示完全不同,有时甚至是“ leaks ”。例如,言语带有情感底蕴,很难用书面形式传达。因此,录音和相同单词的笔录可能会对观众产生很大的影响。换句话说,单词的抽象经常泄漏。

抽象通常是分层的。词是可以用字母表示的抽象,而字母本身又是声音的抽象,而声音又是声音的运动模式的抽象,该运动是由人的声带产生的,并由人的耳鼓检测到的。

在计算机科学中,位通常是最低的表示形式。字节,内存位置,汇编指令和CPU寄存器是下一个抽象级别。然后,我们获得了高级数据类型的原始数据类型和指令,这些数据类型和指令以字节,内存位置和汇编指令的形式实现。然后根据原始数据类型实现并内置于语言指令中的函数和类(假设OO=语言)。然后,根据较简单的函数和类来实现更复杂的函数和类。这些函数和类中的所有函数和类实现数据结构,例如列表,堆栈,队列等。这些结构又用于表示更特定的实体,例如流程队列,员工列表或书名哈希表。在这种情况下,每个级别都是相对于其前身的抽象。

1
Dima

Merriam-webster将抽象定义为形容词存在:与任何特定实例无关。

抽象是某些系统的模型。它们通常列出了一组真实的系统要能够通过抽象建模所必须满足的假设,并且它们通常用于允许我们对日益复杂的系统进行概念化。从实际系统转到抽象没有任何正式的数学方法可以这样做。这取决于谁在定义抽象,以及抽象的目的是什么。

但是,通常情况下,抽象是根据数学结构定义的。那可能是因为它们在科学和工程学中经常使用。

一个例子是牛顿力学。它假设所有事物都无限小,并且所有能量都是守恒的。对象之间的相互作用由数学公式明确定义。现在,正如我们所知道的,宇宙并不是那样工作的,并且在许多情况下抽象会泄漏出去。但是在很多情况下,它都可以很好地工作。

另一个抽象模型是典型的线性电路元件,电阻器,电容器和电感器。同样,通过数学公式清楚地定义了相互作用。对于低频电路或简单的继电器驱动器等,RLC分析效果很好,并提供了很好的结果。但是在其他情况下(例如微波无线电电路),元素太大,并且交互作用也更好,并且简单的RLC抽象也无法成立。此时该做什么取决于工程师的判断。有些工程师在其他工程师的基础上又创建了另一种抽象,有些工程师用新的数学公式代替理想的运算放大器,以了解其工作原理,有些工程师则用模拟的实际运算放大器代替了理想的运算放大器,而后者又由一个较小的复杂网络进行了仿真。理想元素。

正如其他人所说,这是一个简化的模型。它是用于更好地了解复杂系统的工具。

1
whatsisname

编程抽象是某人对编程元素进行的抽象。假设您知道如何使用菜单项和菜单项构建菜单。然后,有人看到了这段代码和思想,嘿,这可能对其他种类的类似租用结构的结构很有用,并且将Component Design Pattern定义为,是第一段代码的抽象。

面向对象的设计模式是抽象的一个很好的例子,我并不是说真正的实现,而是我们应该采用的解决方案。

因此,总而言之,编程抽象是一种使我们能够理解问题的方法,它是获得某些东西的手段,但它并不真实。

0
guiman

对我来说,抽象是“字面上”不存在的东西,就像是一个想法。如果您用数学的方式表达它,那么它就不再是抽象的,因为数学是一种表达大脑中发生的事情的语言,因此它可以被其他人的大脑理解,因此您无法构建自己的想法,因为如果这样做,那不是一个想法不再:您将需要了解大脑如何表达思想模型。

抽象是使您能够将现实解释为可以独立于现实的事物的某种东西。您可以抽象一个海滩和一个梦,但是海滩存在,但梦不存在。但是您可以说两者都存在,但这不是事实。

抽象中最困难的事情是找到一种表达它的方法,以便其他人可以理解它,从而可以将其变为现实。那是最艰巨的工作,而且它真的不能独自完成:您必须发明一个适用于您的想法并且可以被其他人理解的相对模型。

对我来说,计算机语言中的抽象应该被称为“数学化”模型,它是关于重用可以交流的思想,与可以抽象地实现的思想相比,这是一个巨大的约束。

简单地说,原子是紧挨着的,但它们不在乎。组成人类的大量分子可以理解他在某个人的旁边,但是却无法理解,这只是原子如何将自己定位成某种模式。

通常,由一个概念统治的对象无法“理解”自身。这就是为什么我们试图信仰上帝,为什么我们很难理解我们的大脑。

我现在可以拿我的勋章吗?

0
jokoon

这是一个非数学的答案:

Abtracting在编程中假装您现在不在乎细节,而实际上您应该并且一直在乎它们。基本上是假装。

0
mojuba

有趣的问题。我不知道抽象的单一定义在编程时被认为是权威的。尽管其他人已经提供了CS理论或数学各个分支的一些定义的链接;我喜欢以类似于“超级便利”的方式来考虑它,请参阅 http://en.wikipedia.org/wiki/Supervenience

当我们谈论编程中的抽象时,我们实质上是在比较系统的两个描述。您的代码是程序的描述。您的代码抽象也将是对该程序的描述,但级别更高。当然,您可以对原始抽象进行更高级别的抽象(例如,高层系统体系结构中的程序描述与详细设计中程序的描述)。

现在,是什么使一个描述比另一个描述“更高级”。关键是“多重可实现性”-您可以使用多种语言以多种方式实现对程序的抽象。现在您可能会说,一个人也可以为一个程序制作多个设计-两个人可以制作两个可以准确描述程序的不同的高级设计。实现的等价性有所不同。

在比较程序或设计时,必须以允许您确定该级别描述的关键属性的方式进行。您可以说一个设计等同于另一个设计的复杂方法,但是最简单的思考方法是:一个二进制程序可以满足两个描述的约束吗?

那么,是什么使一个描述级别高于另一个描述级别?假设我们有一个级别的描述A(例如设计文档)和另一个级别的描述B(例如源代码)。 A比B高,因为如果A1和A2是A级的两个非等效描述,那么这些描述B1和B2的实现也必须在级别B上是非等效的。但是,相反的情况不一定成立。

因此,如果我无法生成满足两个不同设计文档的单个二进制程序(即这些设计的约束会相互矛盾),则实现这些设计的源代码必须不同。但是,另一方面,如果我采用两组无法编译到同一二进制程序中的源代码,那么仍然可能是由于编译这两套源代码而产生的二进制文件都满足相同的设计文献。因此,设计文档是源代码的“摘要”。

0
wahbedahbe