对于程序员所使用的编程抽象,是否存在公认的定义?[请注意,不要将编程抽象与“抽象”一词的字典定义混淆。]是否存在明确的甚至是数学的定义?有哪些清晰的抽象示例?
对于程序员所使用的编程抽象,是否存在公认的定义?[请注意,不要将编程抽象与“抽象”一词的字典定义混淆。]是否存在明确的甚至是数学的定义?有哪些清晰的抽象示例?
Answers:
答案是“您可以在数学上定义编程抽象或多或少吗?” 没有。” 抽象不是数学概念。这就像要求某人用数学解释柠檬的颜色。
但是,如果您想要一个好的定义:抽象是从特定思想转变为更笼统的思想的过程。例如,看看您的鼠标。无线吗?它有什么样的传感器?多少个按钮?符合人体工程学吗?它有多大?所有这些问题的答案都可以准确地描述您的鼠标,但是无论答案是什么,它仍然是鼠标,因为它是带有按钮的定点设备。这就是鼠标的全部条件。“ Silver Logitech MX518”是一个具体的具体项目,“鼠标”是该项目的抽象。要考虑的重要一点是,没有像“鼠标”这样的具体对象,这只是一个想法。桌上的鼠标总是更具体-
您可以根据需要分层抽象和任意细化(MX518是鼠标,这是一个指针对象,这是一个计算机外围设备,这是一个用电供电的对象),可以随意扩展,并且几乎在任何方向上都可以使用(我的鼠标有一根导线,这意味着我可以将其归类为带有导线的对象。它也平放在底部,因此我可以将其归类为一种在滚动时不会滚动的对象垂直放置在倾斜的平面上)。
面向对象的编程建立在抽象,抽象或抽象组的概念上。好的OOP意味着在适当的细节级别上选择好的抽象,这些抽象在您的程序域中有意义,并且不会“泄漏”。前者意味着将鼠标分类为不会在倾斜平面上滚动的对象对于库存计算机设备的应用程序没有任何意义,但对物理模拟器而言却有意义。后者意味着您应避免将“装箱”到对于某种对象没有意义的层次结构中。例如,在上面的层次结构中,我们确定所有电脑外围设备是用电供电的吗?手写笔呢?如果要将触控笔归为“外围设备”类别,则会遇到问题,因为它不使用电能,并且我们将计算机外围设备定义为使用电能的对象。的圆椭圆问题是这一难题的最有名的例子。
我完全不同意大多数答案。
这是我的答案:
给定两个集合G和H,可以在它们之间定义Galois连接(alpha,beta),可以说一个是另一个的具体化。反向连接,一个是另一个的抽象。这些函数是具体化函数和抽象函数。
这是基于计算机程序抽象解释的理论,该理论通常是迄今为止的静态分析方法。
抽象更多地关注What
而不是更多How
。或者您可以说,只知道您需要做的事情,并且仅信任提供者提供的所有其他服务。有时甚至会隐藏服务提供商的身份。
例如,此站点提供了一个用于提问和回答的系统。这里几乎每个人都知道本网站进行询问,回答,投票和其他操作的程序。但是很少有人知道什么是底层技术。就像该站点是使用ASP.net mvc还是Python开发的一样,它是否运行在Windows或Linux服务器等上,因为这与我们无关。因此,该站点在其底层机制上为我们提供服务保留了一个抽象层。
其他一些例子:
汽车隐藏了所有机械装置,但提供了一种驱动,加油并将其维护的方法。
任何API都会隐藏其所有实现细节,从而向其他程序员提供服务。
OOP中的一个类隐藏其私有成员,并隐藏公共成员的实现,以提供呼叫公共成员的服务。
在Java或C ++ 中使用Interface
或类型的对象时abstract class
,实际的实现是隐藏的。不仅被隐藏,Interface
在各种已实现/继承的类中,中声明的方法的实现也可能会有所不同。但是,当您获得相同的服务时,只需不必理会How
它的实现情况,而正是Who
/ What
正在提供该服务。
隐藏身份信息:表示“我知道Sam可以编写计算机程序”。抽象可以是“ Sam是一名程序员。程序员知道如何编写计算机程序。” 在第二句话中,人并不重要。但是他的编程能力很重要。
How
有助于理解What
s。因此,它可以与抽象混合。
抽象只是定理的编程版本。
您有一个正式的系统,并提出了关于该系统的想法。您对此进行证明,如果可以解决,那么您就有一个定理。知道您的定理成立后,您便可以将其用于有关系统的进一步证明。系统提供的基元(例如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。因此,我的类型系统支撑了我另一个证明的结果!
多年来,许多程序员和许多代码行使这种想法复杂化,您拥有了现代的编程语言:丰富的原语集和庞大的“经过验证的”代码抽象库。
维基百科的答案足够好吗?http://en.wikipedia.org/wiki/Abstraction_%28programming%29
在计算机科学中,抽象的机制和实践减少并分解了细节,以便人们一次可以专注于几个概念。
从数学上来说,“整数”是一个抽象。当您对所有整数进行形式为x + y = y + x的形式证明时,您正在使用抽象“整数”而不是特定的数字(如3或4)。当您与机器位于寄存器和存储器位置之上的级别。在大多数情况下,您可以在更抽象的层次上思考更强大的思想。
IInt add(IInt a, IInt b);
在您事先知道的程序中使用和子例程,a
或者b
会成为Int128: IInt
一个或多或少的好例子?-即您让您的代码段执行了应该做的事情,知道(能够证明)它将完成您需要的事情,同时(另一方面)使您可以使其完全完成您要做的事情是否需要在不知道的情况下(也可以在其他环境中使用该功能)?
add(int, int)
子例程/函数来实现。仅return 2 + 3;
在这种情况下拥有它就足够了。以及为什么要使用更“通用”的例程(return a + b;
即对提供的任何实际 参数a
和b
参数进行操作,从而真正从其值中抽象出来),这是我上面的(修辞性)问题。希望现在变得更加清晰了。
您在这里得到了很好的答案。我只警告您-人们认为抽象是某种奇妙的东西,需要放在基座上,而您可能还不够。它不是。这只是常识。它只是识别事物之间的相似性,因此您可以将问题解决方案应用于一系列问题。
请允许我
在我的烦恼列表中,最重要的是人们谈论“抽象层”时,好像这是一件好事。他们围绕他们不喜欢的类或例程创建“包装器”,并称其为“更抽象”,似乎会使它们变得更好。还记得《公主与豌豆》的寓言吗?公主是如此的娇柔,以至于如果她的床垫下面有豌豆,她将无法入睡,而增加更多的床垫也无济于事。添加更多“抽象”层会有所帮助的想法就是这样-通常不会。这仅意味着对基本实体的任何更改都必须通过多层代码来体现。
我认为您可能会发现有关泄漏抽象的博客文章很有用。相关背景如下:
抽象是一种机制,可以帮助利用一组相关程序片段之间的共同点,消除它们之间的差异,并使程序员能够直接使用代表该抽象概念的构造进行工作。这个新构造(实际上)总是具有参数化:一种自定义构造使用方式以适应您的特定需求的方法。
例如,一个List
类可以抽象出一个链表实现的细节-在这里,您无需考虑操纵next
和previous
指针,而可以考虑在序列中添加或删除值的级别。抽象是从更少的一组更原始的概念中创建有用,丰富,有时甚至复杂的功能的基本工具。
抽象与封装和模块化有关,而这些概念经常被误解。
在该List
示例中,封装可用于隐藏链接列表的实现细节。例如,在面向对象的语言中,您可以将next
和previous
指针设为私有,其中仅允许List实现访问这些字段。
封装不足以进行抽象,因为它不一定意味着您对结构有新的或不同的概念。如果所有List
类都给了您' getNext
'/' setNext
'样式访问器方法,它将从实现细节中封装您(例如,您是否将字段命名为' prev
'或' previous
'?它的静态类型是什么?),但是它将会具有非常低的抽象度。
模块化与信息隐藏有关:在接口中指定了稳定的属性,并且模块实现了该接口,并将所有实现细节保留在模块内。模块化可帮助程序员应对变化,因为其他模块仅依赖于稳定的接口。
封装可以帮助信息隐藏(这样,您的代码就不必依赖不稳定的实现细节了),但是对于模块化而言,封装不是必需的。例如,可以实现一个List
用C结构,露出“ next
”和“ prev
”指针的世界,也提供了一个接口,包含initList()
,addToList()
和removeFromList()
职能。只要遵循接口的规则,就可以保证某些属性将始终保持不变,例如确保数据结构始终处于有效状态。[例如,Parnas关于模块化的经典论文是用汇编示例编写的。该接口是合同和设计的一种交流形式,尽管我们今天依靠它,但不一定必须对其进行机械检查。]
尽管将抽象,模块化和封装之类的术语用作正面的设计描述,但重要的是要意识到,存在以下任何一种特性并不能自动为您提供良好的设计:
如果n ^ 3算法被“很好地封装”,它的性能仍然会比改进的n log n算法差。
如果某个接口适用于特定的操作系统,那么,例如,当需要将视频游戏从Windows移植到iPad时,模块化设计的优势将无法实现。
如果创建的抽象暴露了太多无关紧要的细节,那么它将无法使用其自身的操作来创建新的构造:它只是同一事物的另一个名称。
抽象是指当您忽略被认为无关的细节而赞成被认为相关的细节时。
抽象包括封装,信息隐藏和概括。它不包含类推,隐喻或启发式方法。
任何用于抽象概念的数学形式主义本身都将是抽象,因为它必然要求将基础事物抽象为一组数学属性!态射的范畴理论概念可能最接近您要寻找的概念。
抽象不是您声明的东西,而是您要做的事情。
您可能要查看Bob Martin的一些指标
http://en.wikipedia.org/wiki/Software_package_metrics
就是说,我认为他的“抽象性”与您的不同。他的方法更多地是“缺乏对类的实现”的一种度量,意味着使用接口/抽象类。与主序列的不稳定性和距离可能会在您要寻找的内容中发挥更大的作用。
Merriam-webster将抽象定义为形容词存在:与任何特定实例无关。
抽象是某些系统的模型。它们通常列出了一组真实的系统要能够通过抽象建模所必须满足的假设,并且它们通常用于允许我们概念化日益复杂的系统。从实际系统转到抽象没有任何正式的数学方法可以这样做。这取决于谁在定义抽象,以及抽象的目的是什么。
但是,通常情况下,抽象是根据数学构造来定义的。那可能是因为它们在科学和工程学中经常使用。
一个例子是牛顿力学。它假设所有事物都无限小,并且所有能量都是守恒的。对象之间的相互作用由数学公式明确定义。现在,正如我们所知道的,宇宙并不能完全按照这种方式工作,而且在许多情况下,抽象会泄漏出去。但是在很多情况下,它都可以很好地工作。
另一个抽象模型是典型的线性电路元件,电阻器,电容器和电感器。同样,通过数学公式清楚地定义了相互作用。对于低频电路或简单的继电器驱动器等,RLC分析效果很好,并提供了很好的结果。但是在其他情况下(例如微波无线电电路),元素太大,并且交互作用也更好,并且简单的RLC抽象也无法成立。此时该做什么取决于工程师的判断。有些工程师在其他工程师的基础上又创建了另一种抽象,有些工程师用新的数学公式代替理想的运算放大器以了解其工作方式,有些工程师则用模拟的实际运算放大器代替了理想的运算放大器,而后者又是由较小的复杂网络模拟的。理想元素。
正如其他人所说,这是一个简化的模型。它是用于更好地了解复杂系统的工具。
Employer
基于的假设Employee
)。
抽象是用其他东西来表示某些东西(例如,概念,数据结构,函数)。例如,我们使用文字进行交流。单词是一个抽象实体,可以用声音(语音)或图形符号(书写)表示。抽象的关键思想是,所讨论的实体与基础表示形式有所不同,就像单词不是用来说出它的声音还是用来写出它的字母一样。
因此,至少在理论上,抽象的基础表示可以用其他表示代替。但是,实际上,抽象很少与底层表示完全不同,有时表示会“ 泄漏 ” 出去。例如,言语带有情感底蕴,很难用书面形式传达。因此,录音和相同单词的笔录可能会对观众产生很大的影响。换句话说,单词的抽象经常泄漏。
抽象通常是分层的。词是可以用字母表示的抽象,而字母本身又是声音的抽象,而声音又是声音的运动模式的抽象,该运动是由人的声带产生的,并由人的耳鼓检测到的。
在计算机科学中,位通常是最低的表示形式。字节,内存位置,汇编指令和CPU寄存器是下一个抽象级别。然后,我们获得了高级语言的原始数据类型和指令,这些数据类型和指令以字节,内存位置和汇编指令的形式实现。然后是根据原始数据类型实现并内置于语言指令中的函数和类(假定为OO语言)。然后,根据较简单的函数和类来实现更复杂的函数和类。其中一些功能和类实现数据结构,例如列表,堆栈,队列等。这些功能和类又用于表示更具体的实体,例如流程队列,员工列表或书名哈希表。
int
小于(MAX_INT_SIZE / 2-1)的值,并返回另一个两倍的例程:int f(int a) { return a*2; }
2.一个“处理程序”,其原型void (*) (void)
应在...调用者的合同-都代表抽象(1-实现细节(我们已经提供了,但是对于那些无法访问源代码的人来说是不可用的)),2--处理程序的确切含义确实(但是请注意,这对于分配处理程序的人员是已知的))并且不会泄漏
我尝试向人们描述的一种方法,可能不是最好的方法
考虑一个将2 + 2相加并输出4的程序
考虑一个程序,该程序将用户输入的两个数字相加,x + y = z
哪个更有用和更通用?
我认为抽象是隐藏不必要细节的东西。过程是最基本的抽象单元之一。例如,当我从文件中读取数据时,我不想担心如何将数据保存到数据库中。因此,我创建了一个save_to_database函数。
抽象也可以结合在一起以形成更大的抽象。例如,功能可以放在一个类中,类可以放在一个程序中,程序可以放在一个分布式系统中,等等。
save_to_database
不必担心数据的存储准确度!即会有提供(抽象“相对”到一些代码段)详情反正一个地方,这是明智地选择它的只是这件事-为更容易“改变主意”,等等
我一直认为编程中的抽象是隐藏细节并提供简化的界面。这是程序员可以将艰巨的任务分解为可管理的部分的主要原因。通过抽象,您可以为部分问题创建解决方案,包括所有详细的细节,然后提供一个简单的界面来使用该解决方案。然后,您实际上可以“忘记”详细信息。这很重要,因为一个人无法立即将一个超级复杂系统的所有细节都牢记在心。这并不是说抽象底层的细节永远都不需要重新讨论,而是暂时只记住接口。
在编程中,此简化接口可以是从变量(抽象一组位并提供更简单的数学接口)到函数(抽象处理量到单个行调用中)到类以及其他任何东西。
最后,程序员的主要工作是通常将所有计算细节抽象出来,并提供一个简单的界面(如GUI),一个对计算机工作原理一无所知的人可以利用。
抽象的一些优点是:
允许将大问题分解为可管理的部分。当将一个人的记录添加到数据库中时,您并不需要在数据库上插入和平衡索引树而感到麻烦。这项工作可能在某个时候已经完成,但是现在已经被抽象掉了,您不必再为它担心。
允许多个人一起完成一个项目。我不想知道我同事代码的所有内容。我只想知道如何使用它,做什么以及如何将其与我的作品(界面)配合使用。
允许没有必要知识的人执行复杂的任务。我妈妈可以更新她的Facebook,她在全国各地认识的人都可以看到它。没有一个疯狂的复杂系统到一个简单的Web界面的抽象,她就不可能开始做类似的事情(我也不会这样做)。
但是,抽象可能会产生相反的效果,如果过度使用抽象,它会使事情变得难以管理。通过将问题分解为许多小片段,您必须记住的接口数量会增加,并且很难理解真正的情况。像大多数事物一样,必须找到平衡点。
间接的额外级别。
您不需要关心所使用的对象是a Cat
还是a Dog
,因此您可以通过虚函数表查找正确的makeNoise()
函数。
我确定这也可以应用于“较低”和“较高”级别-想一想编译器查找正确指令以用于给定处理器或Haskell Monad
通过调用all return
和来抽象计算效果>>=
。
这实际上是我想写博客的时间更长的时间,但是我从来没有去过。幸运的是,我是代表僵尸,甚至还有赏金。我的帖子结果相当冗长,但这是本质:
编程中的抽象是关于在给定上下文中理解对象的本质的。
[...]
抽象不仅被误认为是泛化,而且还被封装所误解,但这是信息隐藏的两个正交部分:服务模块决定其愿意展示的内容,客户端模块决定其愿意看到的内容。封装是第一部分,而抽象则是后者。只有两者一起构成完整的信息隐藏。
希望能有所帮助。
这是一个非数学的答案:
精疲力尽的编程是假装您现在不在乎细节,而实际上您确实在乎,应该一直在关心它们。基本上是假装。
对我来说,抽象是“字面上”不存在的东西,就像是一个想法。如果您以数学方式表达它,那么它就不再是抽象的,因为数学是一种表达大脑中发生的事情的语言,因此它可以被其他人的大脑理解,因此您无法构建自己的想法,因为如果这样做,那么它就不是一个想法不再:您将需要了解大脑如何表达思想模型。
抽象是使您可以将现实解释为可以独立于现实的事物。您可以抽象一个海滩和一个梦,但是海滩存在,但梦不存在。但是您可以说两者都存在,但这不是事实。
抽象中最困难的事情是找到一种表达它的方法,以便其他人可以理解它,从而使其变为现实。那是最艰巨的工作,而且它真的不能独自完成:您必须发明一个适用于您的想法并且可以被其他人理解的相对模型。
对我来说,计算机语言中的抽象应该被称为“数学化”模型,它是关于重用可以交流的思想,与可以抽象地实现的思想相比,这是一个巨大的约束。
简而言之,原子彼此相邻,但它们不在乎。组成人类的大量分子可以理解他在某个人的旁边,但是却无法理解,这只是原子如何将自己定位成某种模式。
通常,由一个概念所统治的对象无法“理解”自身。这就是为什么我们试图信仰上帝,为什么我们很难理解我们的大脑。
我现在可以拿起勋章吗?
有趣的问题。我不知道抽象的单一定义在编程时被认为是权威的。尽管其他人提供了CS理论或数学各个分支的一些定义的链接;我喜欢以类似于“ supervenience”的方式来思考它,请参见http://en.wikipedia.org/wiki/Supervenience
当我们谈论编程中的抽象时,我们实质上是在比较一个系统的两个描述。您的代码是程序的描述。您的代码抽象也将是对该程序的描述,但级别更高。当然,您可以对原始抽象进行更高级别的抽象(例如,高层系统体系结构中的程序说明与详细设计中程序的说明)。
现在,是什么使一个描述比另一个描述“更高级”。关键是“多重可实现性”-您可以使用多种语言以多种方式实现对程序的抽象。现在您可能会说一个人也可以为一个程序制作多个设计-两个人可以制作两个不同的高级设计,两个设计都能准确地描述该程序。实现的等价性有所不同。
在比较程序或设计时,必须以允许您确定该级别描述的关键属性的方式进行。您可以说一个设计等同于另一个设计的复杂方法,但是最简单的思考方法是:一个二进制程序可以满足两个描述的约束吗?
那么,是什么使一个描述水平高于另一个描述水平?假设我们有一个级别的描述A(例如设计文档)和另一个级别的描述B(例如源代码)。A比B更高的水平,因为如果A1和A2是两个非等价的描述在电平A,则这些描述的实现中,B1和B2 必须也有非等效于电平B.但是,反向不一定保持为真。
因此,如果我无法生成一个满足两个不同设计文档的二进制程序(即那些设计的约束会彼此矛盾),那么实现这些设计的源代码必须是不同的。但是,另一方面,如果我采用了两组无法编译到同一二进制程序中的源代码,那么仍然可能是由于编译这两套源代码而产生的二进制文件都满足相同的设计文献。因此,设计文档是源代码的“摘要”。