作为结构化编程的一种,函数式编程正受到越来越多的重视。而作为常用的一种程序开发方法,面向对象编程为程序设计带来了更强的灵活性和可维护性。那么两者相较而言,究竟有着什么样的区别?应用场景又有何不同?
作者 |Reginald Braithwaite
译者 | 彼得
责编 | 屠敏
出品 | CSDN(ID:CSDNnews)
简单来说,函数式编程(“FP”)和面向对象编程(“OOP”)具有相似的表达能力和封装能力,它们都可以将程序封装成可以自由组合的较小部分。
但是这两个“思想流派”之间的还是存在着很多区别。其中最大的差别在于对数据和数据操作之间关系的不同处理。
FP 和 OOP 的区别
面向对象编程的核心思想是将数据和对数据的操作进行紧密耦合:一个对象除了拥有自己的数据,还拥有对数据操作的实现。这些对象对外隐藏这些具体的信息。它们通过接口,进行响应的方法或消息来和其它对象交互。 因此,在面向对象编程中,抽象的核心是数据,这些数据通过接口等API对外展示。
在面向对象编程中,人们所作的主要工作就是创建新对象或者通过增加新方法来扩展现有对象。
函数式编程的核心原则是数据只与功能进行松散的耦合。你可以对同一个数据结构定义不同的操作。在这里,抽象的核心是函数,而不是数据结构。函数隐藏了它们的具体实现、编程语言的抽象以及函数之间进行组合或表达的方式,例如泛型函数或组合函数。
在函数式编程里,人们的主要工作就是编写新函数。
在自然界中,如果熊和鳄鱼之间爆发冲突,地形会决定双方争斗的结果。
对于函数式编程和面向对象编程来讲,它们在什么情况下,其中的一个比另一个更合适呢? 因为这是一个实用的博客,所以,我将忽略所有理论上的考虑因素,例如机械地推理代码的能力和实施项目时的限制条件,比如资源不足,时间不足等。
在实际的环境中,你认为这两者中的任何一个会是压倒性的“赢家”吗?这个可能得花些时间好好想想。在你思考的时候,我会先享受一杯浓咖啡...
何时使用 FP?何时使用 OOP?
当然,答案是,业务编程主要是由功能模型,而不是面向对象模型进行控制的。 这是一个让你觉得惊讶的答案吗?如果你的头脑里只考虑Java,C ++,C#和Ruby,也许这个答案会令你觉得奇怪。
你知道,所有的面向对象通常都是对访问各种支持 SQL 的数据库的模拟。 SQL是一种非常实用的数据库操作的脚本语言。你可以对数据库进行设定,使得对它所有表格的访问都是通过PL/SQL的存储过程完成的,但是因为这样会产生严重的编程问题,所以,实际中很少这样做。
关系型数据库的主要好处是它可以满足未来的需求。如果你需要新的报告,那随时可以创建它们。许多不同的应用程序可以与同一个数据库进行通信。这些程序之间的数据一致性可以通过数据库的约束条件来强制实现。
如果你仔细研究一下,就会发现数据库本身其实就是一个大的数据结构,而应用程序则是对数据库中的数据进行的操作。几乎每个商务应用的核心都是一个大的功能性的数据库,也就是一个数据结构和一系列对数据进行的操作。
OOP 使用场景
但是,我们在应用程序中包含对象只是为了符合潮流吗? 或者说,我们在编写应用程序时做的事情和创建数据库时做的事情有什么本质上的不同吗?
这个问题答案就在于面向对象和使用数据库各自有什么好处。
一个精心设计的面向对象的架构可以轻松改变对象的组合方式。 隐藏实现和解耦使您可以轻松地更改对象之间的关系。使用面向对象本身,并不会使添加新的操作变得更容易。如果在代码中发现双重调度和访问的问题,你就能够真正地感受到这一点。
但是,假如有一个订单处理系统,如果你的业务规则发生了变化,需要相应地修改订单的处理流程,你就会发现面向对象的优势。 那些不受这些变化影响的对象和受影响的对象是互相隔离的。
另一方面,精心设计的数据库会使添加新查询和操作变得很容易。如果你需要以新的方式查看现有的数据或者如果您需要向数据添加新的更新类型,它都能够很好地处理。 客户端应用程序在逻辑上与提高性能的索引等问题互相隔离。
这样做并不会使改变关系变得更容易。如果更改管理结构,使报表和管理器的关系从一对一变为多对多的矩阵管理结构,那么这种更改将破坏许多应用程序。
因此,如果我们记录了所有在商业软件中需要实现的内容,我们需要把那些代表长期的、相对不变的关系的东西放在数据库中保存,把那些代表短期操作、随着时间的推移而发展和变化的内容,在应用程序中实现。
应用程序的堆栈通常比数据库的堆栈高四倍,这很正常。事情确实发生了变化,企业也应该不断地学习、成长和发展。
FP 的应用场景
那么,我们通常所说的函数式编程,也就是用多范式语言中的函数式编写的代码怎么做?我们可以简单地将面向对象程序改写为作用于相对静态的数据结构上的操作集合吗?
通常来说,这样都是可以的。但同时必须优先考虑这种关系的相对寿命。那些本身不太可能改变,但是被经常改变的实体所操作的内容应该以一种函数式编程来实现,而那些相对经常改变的东西可以用面向对象的风格来实现。
如果每个管理器都有一个或多个报表,并且每个报表都只有一个管理器,那么将这种关系通过API进行隐藏就几乎没有什么好处了,因为在API中,管理器对象以隐含的方式来委托操作。对于这种关系,最好的处理方式是先构造数据,然后对数据进行操作。
但是关于运输成本的规则很可能会改变,所以,最好你把它封装起来,以便程序的其它部分不被将来可能的变化所影响。
因为好的软件需要满足不止一种需求,所以,它们一般都包含这两种风格。
原文: http://raganwald.com/2013/04/08/functional-vs-OOP.html
作者简介: Reginald Braithwaite,他的兴趣包括构造超现实数字,析构空值,以及庆祝编程的乐趣。他是JavaScript Allongé、CoffeeScript Ristretto和raganwald.com的作者。他在pagerduty开发用户体验.
本文为 CSDN 翻译,如需转载,请注明来源出处。
热 文推 荐
领取专属 10元无门槛券
私享最新 技术干货