今天我们就来说说面向对象编程中比较难的问题。在1960年代,编程有一个大问题:计算机还没有那么强大,需要以某种方式平衡数据结构和程序之间的力量。这意味着,如果您拥有大量数据,则如果不将计算机推向极限,就无法充分利用这些数据。另外,如果你需要做很多事情,那么你不能使用太多的数据,否则计算机将永远运行下去。然后是1966年、1967年,AlanKay从理论上证明了可以使用封装的微型计算机。这些微型计算机不共享数据,而是通过消息传递进行通信。这导致更经济地使用计算资源。尽管这个想法很巧妙,但直到1981年面向对象编程才成为主流。从那时起,它就一直在吸引新的和有经验的软件开发人员。面向对象的程序员市场一如既往地繁忙。但近年来,这种已有数十年历史的编程范式受到越来越多的批评。经过40年的面向对象编程,技术是否已经超越了这种范式?上面文章链接:https://towardsdatascience.com/why-developers-are-falling-in-love-with-functional-programming-13514df4048e函数和数据耦合面向对象编程的主要思想很简单:trytocombinapowerful把程序作为一个整体分解成多个功能同样强大的部分。这使得可以将一些数据与仅适用于相关数据的函数结合起来。请注意,这仅涵盖封装的概念。也就是说,位于对象内部的数据和函数对外是不可见的。我们只能通过消息(通常通过getter和setter函数)与对象的内容进行交互。继承和多态性并没有包含在最初的设计思想中,但却是当今面向对象编程所必需的。继承基本上意味着开发人员可以定义具有其父类的所有属性的子类。继承直到1976年才被引入,这比面向对象编程的概念晚了十年。又过了十年,多态性才进入面向对象编程。简单来说,这意味着某个方法或对象可以用作其他方法或对象的模板。从某种意义上说,多态性是继承的泛化,因为并非原始方法或对象的所有属性都需要转移到新实体。相反,您还可以选择覆盖某些属性。多态的特别之处在于,即使两个实体在源代码中相互依赖,被调用实体的工作方式更像是一个插件。这让开发人员的生活更轻松,因为他们不必担心运行时依赖性。值得一提的是,继承和多态性并不是面向对象编程所独有的。真正的区别是封装的数据和它包含的方法。在计算资源远比今天稀缺的时代,这是一个天才的想法。面向对象编程中的前5个问题面向对象编程一经问世,就改变了开发人员查看代码的方式。在80年代之前,过程式编程非常面向机器。开发人员需要了解很多关于计算机如何工作才能编写出好的代码。面向对象编程通过封装数据等方法,使软件开发更加以人为本,更符合人的直觉。例如,方法drive()属于car数据组,而不是teddybear组。后面出现的继承也很直观。例如,Hyundai是Car的子类并且具有相同的属性,但PooTheBear不是,这是有道理的。BananaMonkeyJungleProblem假设您正在设置一个新程序并且您正在考虑设计一个新类。然后,您回想起为另一个项目创建的一个简洁的小类,并发现它非常适合正在进行的工作。没问题,您可以在新项目中重用以前项目中的类。问题来了:这个类可能是另一个类的子类,所以你还需要包含它的父类。然后你会发现这个父类也可能是另一个类的子类,等等,最后不得不面对一堆代码。Erlang的创造者JoeArmstrong有一句名言:“面向对象语言的问题在于它们周围都有自己的隐式环境。你想要香蕉,但你得到的是一只拿着香蕉的大猩猩和一整片丛林。””这几乎说明了一切。重用类是可以的,事实上这可能是面向对象编程的主要优势,但不要走极端。有时你应该构建一个新类而不是添加很多依赖项.脆弱的基类问题想象一下,如果您已经成功地将另一个项目中的类重用于新代码,如果基类发生变化会发生什么情况?这可能会破坏整个新项目的代码,即使您可能什么都没做。有人改变了基类中对你的项目至关重要的细节,影响会很大而且突然。你使用继承越多,潜在的维护工作就越多。所以即使重用代码在短期内非常有效,从长远来看会让你付出代价。DiamondInheritanceProblem继承用于将属性从一个类传递到其他类。但是如果你想混合两个不同类的属性怎么办?是的,这是做不到的,至少不是常规的方式。以Copier类为例(引用以下链接文章中的示例:https://medium.com/@cscalfani/goodbye-object-oriented-programming-a59cda4c0e53),Copier将扫描文件的内容并打印它在纸上呈白色。那么它应该是Scanner或Printer的子类吗?这个问题根本没有完美的答案。即使这个问题没有破坏您的代码,如此频繁地看到它也会令人沮丧。层次问题在菱形继承问题中,Copier是哪个类的子类是问题的关键。但也许有一个机会主义的解决方案:假设Copier是父类,而Scanner和Printer是只继承一部分属性的子类,那么问题就解决了。但是,如果您的复印机是黑白的,而打印机也可以处理彩色怎么办?从这个意义上说,打印机不就是复印机的概括吗?如果打印机连接到WiFi但复印机没有连接怎么办?您在类上堆积的属性越多,建立适当的层次结构就越困难。在您正在处理的属性集群中,Copier共享一些但不是所有Printer的属性,反之亦然。在大型和复杂的项目中,层次结构问题会导致极大的混乱。引用问题您可能会想到在没有层次结构的情况下进行面向对象的编程。我们可以使用属性集群并根据需要继承、扩展或覆盖属性。也许这有点令人困惑,但这将是手头问题的准确表述。这里只有一个问题:封装的全部意义在于保持数据片段彼此安全,从而使计算更有效率,但如果没有严格的层次结构,那是行不通的。假设对象A通过与另一个对象B交互来覆盖层次结构,会发生什么?其他关系的大小写无关紧要,但是当B不是A的直接父级时,A必须包含对B的所有私有引用,否则它们将无法交互。但是,如果A包含B的子类也具有的信息,则可以在多个位置修改该信息。因此,有关B的信息不再安全,并且封装已被破坏。虽然很多面向对象的程序员都使用这种架构来构建程序,但那不是面向对象的编程,只是乱七八糟。单一范式的风险以上5个问题的共同点是它们都有不适当的继承。由于面向对象程序设计的原始形式中并没有包含继承,所以这些问题可能不能称为面向对象本身的问题。但被夸大的不仅仅是面向对象编程。在纯函数式编程中处理用户输入或将消息打印到屏幕是极其困难的。面向对象或面向过程的编程对此要好得多。但是还是有一些开发者试图用纯函数的方式来实现这些东西,写了几十行没人能看懂的代码。使用另一种范例可以轻松地将代码减少到几行可读代码。毫无疑问,函数式编程越来越受到关注,而面向对象编程近年来受到了一些批评。了解新的编程范例并在适当的时候使用它们是有意义的。不管是哪种编程范式,都不需要只遵循一种。只有在适当的时候使用不同的编程范式,才能更好地解决问题。上面文章链接:https://medium.com/madhash/what-is-better-functional-programming-or-object-oriented-9a116c704420面向对象编程真的要被取代了吗?面对越来越多的问题,函数式编程或许是更有效的选择。数据分析、机器学习、并行编程,在这些领域投入越多,就会越喜欢函数式编程。但是,目前面向对象开发对程序员的需求仍然远高于函数式编程程序员。但这并不意味着你不能成为后者。函数式编程开发的程序员还是比较紧缺的。最有可能的是,面向对象编程将继续存在十年左右。当然,选择一种相对前卫的方法是好的,但这并不意味着你应该放弃面向对象的编程。所以在接下来的几年里,不要完全放弃它,但至少要确保它不是你掌握的唯一编程风格。【本文为栏目组织《机器之心》微信公众号《机器之心(id:almosthuman2014)》原文翻译】点击此处查看作者更多好文
