非OOP范例是否支持封装等概念?


12

面向对象编程中的重要概念之一是封装。但是,最近,软件世界似乎倾向于使用其他范例,例如函数式编程。

这让我思考,封装和其他OOP原则如何?他们错了吗?

OOP应用错误吗?例如,艾伦·凯(Alan Kay)在OOPSLA'97主题演讲中说:“我发明了术语面向对象,我可以告诉你我没有C ++。”

乔·阿姆斯特朗(Joe Armstrong)-“对象将功能和数据结构以不可分割的单位绑定在一起。我认为这是一个根本性的错误,因为功能和数据结构属于完全不同的世界。”




2
我要说的问题首先需要弄清楚封装的含义以及支持它的语言的含义。
欣快的

14
我很难弄清楚这个问题在问什么。是否在问是否可以在OO(主题行)之外存在封装?是否在问封装是否错误(第二段)?它是在问OO是否应用错误(第三段)?OP希望用Joe Armstrong的话说什么?OP如何定义“封装”?OP如何定义“ OO”?这些“其他原则”是什么?
约尔格W¯¯米塔格

1
罗伯特·马丁(Robert Martin)曾经说过,OOP取消了封装,然后用可怕的黑客对其进行了修补。“我们在oo之前完成了完美的封装”。他当然是个双曲线,但是现在每次我看到有人说OO是关于封装时,我都记得Bob叔叔。
GnP

Answers:


15

我认为您陷入的陷阱是,在任何编程范例(结构化,面向对象,功能等)上都有一个严格的定义。

如果您问两个不同的开发人员OOP是什么意思,您将得到两个不同的答案。是的,作为一个职业,我们同意大学中的任何OOP软件工程课程都涉及一些通用主题,例如封装,数据隐藏等。

但是,在现实世界中,事情并没有那么干and,这就是为什么两个开发人员会给出两个不同的答案的原因。也许他们是用不同语言表达OOP概念的专家。语言范式倾向于重叠。截止到2013年左右,最新的风潮是通过闭包或lambda将函数式编程集成到面向对象的语言中。Java 8是面向对象的还是功能性的?我将其称为带有一些功能的面向对象。其他人可能会以不同的方式描述它。

OOP应用错误吗?

不,问题在于各种语言对编程概念的表达方式有所不同。也许一种语言遗漏了一个OOP概念,而另一种语言却包含了它,但遗漏了一个不同的OOP概念。语言通常是出于以下目的而设计的:使某种类型的任务变得容易,但以使其他任务更加困难为代价。这是非非非,只是在现实世界中的折衷,是无法避免的。

现实世界不是教室。我们要么需要在抽象级别上讨论概念上的编程范例,要么我们需要讨论被迫进行权衡才能真正有用的真实编程语言。只要编程语言主要由OOP的抽象定义定义,我们就可以将其包含在该存储桶中。


10

但是,最近,软件世界似乎倾向于使用其他范例,例如函数式编程。

这值得商.。首先,除了OOP和函数式编程之外,我没有看到其他广泛讨论的范式,因此我想我们可以忘记“其他范式”这句话,让我们谈论FP,仅此而已。

在最近的其他问题中,深入讨论了函数式编程之所以如此流行的原因,我不再赘述(例如,参见此处此处)。但是,在我看来,这并不是因为“ OOP是一个大错误”,也不是“功能与OOP是互斥的”,它更像是人们在扩展工具箱并试图同时兼顾两者。好的,肯定有专家,他们是强硬派,一个人又一个人,但您会发现双方都有。

这让我思考,封装和其他OOP原则如何?他们错了吗?

封装具有许多不同的风味。函数式编程语言和语言构造提供了某些封装形式,其他面向对象。如果要查找使用功能性方法进行封装的示例,请从闭包开始。

关于“其他原则”:不,它们没有错,但是对于某些情况,例如大规模并行化,功能方法可能会更好地扩展。对于其他场景,例如创建设计良好的UI框架,OOP方法可能会更好地扩展(YMMV,我手头没有一个更好的示例)。而且,我确信对于大多数实际场景,这取决于团队的知识和经验以及最喜欢的编程范例,该系统将如何扩展。

OOP应用错误吗?例如,艾伦·凯(Alan Kay)在OOPSLA'97主题演讲中说:“我发明了术语面向对象,我可以告诉你我没有C ++。”

当然,很多人经常将OOP应用于错误,但是我确信FP也是如此。如果John Mc Carthy(Lisp的设计师)在考虑函数式编程时想到了类似Javascript的话,我会感到惊讶(对我的怜悯,不要为这个比较而发怒;-)

乔·阿姆斯特朗(Joe Armstrong)-“对象将功能和数据结构以不可分割的单位绑定在一起。我认为这是一个根本性的错误,因为功能和数据结构属于完全不同的世界。”

我想Erlang的发明家有一些很好的论据,但他也有他自己的观点,所以让他发表自己的看法并建立自己的观点。还有很多其他专家对此有不同的想法。


1
我不确定OO对于GUI来说是更好的,更多的是OO和GUI大约是同时出现的。尽管为McCarthy / javascript +1;)
jk。

1
公平地说,有人确实建议现有方法存在缺陷,可以用其他方法代替。我不知道该叫工具箱“扩展”还是“改进” :)
Andres F.

1
@AndresF。这是一个很棒的阅读。我计划在有空的时候详细阅读该论文。
罗伯特·哈维

4

当然:

struct Foo
{
    string bar;
    int bux;
}

我知道您要说的是:“但这还不能封装行为!” 好吧,我与Joe Armstrong在一起:您可以编写整个程序或操作系统,而无需一流的对象。Linux证明了这一点。

Javascript程序员通常将状态和行为封装在函数和闭包中,而不是类中。


3
您也可以只用茶匙铲起泥土。但是任何声称这是最佳方法的人都应该被怀疑。
欣快感'16

6
我从来没有说过它是最佳的,而这并不是OP所要求的。在其他新闻中,我发现Linux具有将一茶匙铲除污垢的资格,这很有趣。
罗伯特·哈维

2
@jk。当然。C也是如此。
罗伯特·哈维

1
的确有点不
JK。

4
我不会将C结构称为“封装”。它们既不保护数据,也不一定提供任何标准化的方法来访问它。它们只是使您免于执行手动指针运算的麻烦。例如,找到将序列化数据包转换为结构的网络代码非常普遍,反之亦然。错误地获得网络字节顺序并随之而来。
david25272 '16

2

这里的主要问题是封装不是严格定义的概念,也不是有用的。做一些研究表明,人们对封装的看法受到了高度评​​价,许多人将其与抽象混淆了。

要找到的第一个定义是

封装是将数据和操纵数据的功能绑定在一起的概念。

如果这是您的定义,那么大多数语言都可以将数据和对该数据进行操作的功能分组为类,模块,库,名称空间等。

但是我认为这不是封装的主要目的,因为该定义仍在继续:

...,这可以确保不受外界干扰和滥用。

维基百科也同意

一种语言机制,用于限制直接访问对象的某些组件。

但是现在,我们需要问什么是“干扰和滥用”,以及为什么应该限制对数据的直接访问。我相信有两个原因。

首先,限制数据可以突变的范围是开发人员的最大利益。通常,在设置值之前/之后需要逻辑。而且只有数量有限的地方可以设置价值是非常有价值的。在OOP语言中,可以使用类来完成。在“可变”功能语言中,闭包具有相同的目的。并且因为我们知道class =闭包,所以甚至比可变功能语言与OOP的不同“范式”更值得争论。

但是不可变语言呢?它没有变异变量的问题。这是第二个问题所在:绑定功能和数据允许将数据保持在有效状态。假设您的拥有不变的结构Email。此结构具有单个string字段。我们有要求,如果您具有类型的值,Email则该字段包含有效地址。在OOP的封装中,只需声明该字段private,仅提供Get方法并具有constructor method仅当传入的字符串是有效地址时成功。闭包也是如此。现在,对于不可变的语言,可能需要说结构只能通过特定的函数进行初始化,而该函数可能会失败。而且我不知道有什么语言可以满足该标准(也许有人在评论中可以启发我)。

最后一个问题是语言“支持”封装的含义。一方面,存在允许强制执行封装的语言,因此如果破坏了封装,则代码不会编译。另一方面,该语言可能提供了进行封装的方法,但它没有强制执行封装,而让开发人员自行执行。对于第二种情况,任何具有结构和功能的语言都可以使用。动态语言和Haskell浮现在脑海。我想说的是,没有另一种语言可供选择。即使是C#(实际上非​​常擅长于对其对象进行封装),也可以使用反射来绕过它。但是看到在C#中将被认为是大量的代码气味,并且没有理智的C#开发人员愿意这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.