面向对象、函数式编程与并行

作者:江宏
链接:https://www.zhihu.com/question/19728806/answer/18575066
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这个问题的根本在于 OOP 是基于状态的。每个对象都维护着自己的状态,暴露给外界的是一些可以改变对象状态的方法。一个对象的状态里可以有对其他对象的引用,一个对象的方法也可以调用其他对象的方法来改变其他对象的状态,所以这些状态还是关联的。很多人提到的线程安全与效率的取舍之类其实都是细枝末节,即使是有办法把所有方法都能高效地实现并且全都是线程安全的,只要状态存在,状态带来的问题就存在。在一个复杂的并发系统中,你调用 foo.bar(42),几个指令之后再调用 foo.bar(42),两次调用的结果很可能是不一样的,因为在这中间 foo 的状态可能已经改变了,或者 foo 引用的某个对象的状态可能改变了,不去看 bar() 的实现根本不知道结果依赖于什么。同样一段程序多次运行因为时序的不确定性可能结果也不一样。不管 OOP 也好,过去说的过程式编程也好,理论基础都是图灵机模型,而图灵机就是依靠对状态的记录和改变来进行运算的。图灵机里的纸带和状态寄存器用来记录状态,而读写头用来访问和改变状态。想象一下一个并行的图灵机(多个有独立状态寄存器和不同速度的读写头加上一条共享的纸带)就不难理解在这个模型下并发带来的复杂度。

而目前很多人因为并发的需求所崇尚的函数式编程是基于 Lambda Calculus 的计算模型。计算由层层嵌套的函数调用完成;每个函数调用的结果只依赖于函数和它的参数。如果 f(4, 5) = 10,那么无论你在什么时候调用 f(4, 5),它的结果都是 10。相对而言,这是一个比较干净,比较容易推理和确保正确性的模型。OOP 的程序通常有很多隐藏的数据依赖,函数式编程把这些数据依赖都明确化了。

但函数式编程最大的一个问题是,函数是一个数学抽象,在现实世界中不存在,它必须被模拟出来。目前为止被广泛使用的计算机还是基于图灵机模型,计算机的寄存器、缓存、内存就是用来记录状态的。要真正懂得程序设计,必须知道没有状态的函数是如何在充满状态的计算机上实现的,所以还是绕不开非函数式的编程。另外绝大部分的函数式程序设计语言都不是纯函数式的,出于实用性考虑都夹杂着其他语言的一些特点,并没有完全排斥状态。Haskell 号称纯函数式语言,用 Monad 来抽象状态,理论上可以自圆其说,但在实际使用中其实还是带来了很多不便(于是又发明了 Monad Transformer...)。

从某种程度上说,状态是绕不过去的,毕竟人感知到的宏观世界就是由各种各样有各自状态的对象构成。函数式编程可以帮我们避免很多用其他方式容易犯的错误,在很多情况下写出更高质量的程序,但并发带来的复杂度并不会从根本上消失。各种编程风格一定是互相影响推动程序设计语言的进化,没有绝对的好坏,从 C++ 和 Java 最新标准里引入的函数式方面的功能就很容易看出这一点。比较有意思的是,OOP 最早是在 LISP 里实现的,而 LISP 也被很多人看做函数式编程的起始。同样,好的程序员也会根据具体情况使用合适的编程风格。

OOP 不失为一种比较容易理解的在计算机程序里对现实世界的抽象,在很多场合的应用是非常成功的,至少我没发现以图形用户界面为中心的程序里有比 OOP 更行之有效的抽象方式。把 OOP 从程序员的教育中去掉过于片面和激进了。如果是从基础课程调整为选修课程则是可以理解的,我上本科时记得也是那样设置的。

原文地址:https://www.cnblogs.com/feng9exe/p/8310175.html

时间: 2024-10-16 07:02:57

面向对象、函数式编程与并行的相关文章

Python-17-函数_06_函数式编程

一.函数式编程---定义:编程的方法论:1.函数式2.面向过程3.面向对象 函数式编程:函数式=编程语言定义的函数+数学意义的函数 简单说:函数式就是用编程语言去实现数学函数 函数式编程,主要在Hsahell.clean.erlang等这几门语言中利用. def cal(x): return 2 * x + 1 # 函数式 a.不可变,不用变量保存状态,不修改变量 def cal(x): # 非函数式 res = 2 * x res += 1 return res # 面向过程 b.第一类对象:

python_way.day7 模块(configparser,xml,shutil,subprocess)、面向对象(上)(创建类,类的构成,函数式编程与面向对象编程的选择,类的继承)

python_way.day7 1.模块 configparser,xml,shutil,subprocess 2.面向对象(上) 创建类,类的构成,函数式编程与面向对象编程的选择,类的继承 1.模块 configparser 用于处理特定格式的文件,其本职上使用open来操作,只能是  [test1] 特定的格式 [test1] k1 = 123 k2 = True [test2] k1 = 123 k2 = v1 文件内容 1.获取 import configparser #打开文件找到文件

函数式编程与面向对象编程的比较

函数式编程作为结构化编程的一种,正在受到越来越多的重视.工程中不在只是面向对象编程,更多的人尝试着开始使用函数式编程来解决软件工程中遇到的问题. 什么是函数式编程?在维基百科中给出了详细的定义,函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象.函数编程语言最重要的基础是λ演算(lambda calculus).而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值

Reactor事件驱动的两种设计实现:面向对象 VS 函数式编程

Reactor事件驱动的两种设计实现:面向对象 VS 函数式编程 这里的函数式编程的设计以muduo为例进行对比说明: Reactor实现架构对比 面向对象的设计类图如下: 函数式编程以muduo为例,设计类图如下: 面向对象的Reactor方案设计 我们先看看面向对象的设计方案,想想为什么这么做: 拿出Reactor事件驱动的模式设计图,对比来看,清晰明了: 从左边开始,事件驱动,需要一个事件循环和IO分发器,EventLoop和Poller很好理解:为了让事件驱动支持多平台,Poller上加

Python进阶 函数式编程和面向对象编程等

函数式编程 函数:function 函数式:functional,一种编程范式.函数式编程是一种抽象计算机的编程模式. 函数!= 函数式(如计算!=计算机) 如下是不同语言的抽象 层次不同 高阶函数:能接收函数做参数的函数 变量可以指向函数 函数的参数可以接收变量 一个函数可以接收另一个函数作为参数 例子: 接收abs函数, 定义一个函数,接收x,y,z三个参数.其中x,y是数值,z是函数 . 1 2 3 def add(x,y,z):     return z(x)+z(y) print ad

面向对象设计思想和函数式编程思想

1.函数式编程思想:核心主体是函数,函数可以作为参数,返回值,具有高度不可变性,是以函数为主体,如果传入参数是相等的,那么返回结果注定是相等. 2.面向对象编程思想:(1)封装:封装变化,可以做到重用,实现代码优雅简洁. (2) 继承: 子类继承父类,实现子类可以继承父类的方法和属性,同时可以自己扩展,实现了代码的可扩展性,让程序更加灵活. (3) 多态:多种形态.说白了就是两种体现形式:第一种就是向上转型,父类可以指向子类,实现多态. 第二种就是方法的重载,一个相同的方法作用给不同的对象,返回

python编程:函数式编程和面向对象编程的对比

言而简之,面向对象编程就是把函数编程外面包装一个class类,然后再把这个class类指向一个对象 而class类中的函数在这里称为方法 举个例子: 用函数式编程写出一键发送邮件的脚本: def e_mail(email,message): print('邮件发送中...') return True e_mail('[email protected]','邮件内容') 用面向对象编程写出一键发送邮件的脚本: class Foo: #e_mail称为方法 def e_mail(self,email

Python 函数式编程和面向对象编程

函数式编程 函数:function.函数式:functional,一种编程范式.函数式编程是一种抽象计算机的编程模式.函数!= 函数式(如计算!=计算机) 如下是不同语言的抽象 层次不同 高阶函数 能接收函数做参数的函数: 1.变量可以指向函数2.函数的参数可以接收变量3.一个函数可以接收另一个函数作为参数 例子 接收abs函数,定义一个函数,接收x,y,z三个参数.其中x,y是数值,z是函数 . def add(x,y,z): return z(x)+z(y) print add(-2,-3,

javascript消除字符串两边空格的两种方式,面向对象和函数式编程

主要是javascript中消除字符串空格,比较两种方式的不同 //面向对象,消除字符串两边空格 String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }; //去左右空格的函数; function trim(s){ return s.replace(/(^\s*)|(\s*$)/g, ""); }调用消除空格的两种方式. var defualtPhone =