面向对象与函数式编程

Posted topgeek

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象与函数式编程相关的知识,希望对你有一定的参考价值。

点击上方 “topgeek” 可以订阅哦!
编者注:
 
【2017架构师大会来啦,见文末】耳熟能详的两个词,你更倾向于哪一种呢? 作者:fsux 原文链接:http://fsux.me/深入浅出/随笔/2016/12/05/Talking-about-programming-type.html

面向对象编程和函数式编程有什么不同,或者你更倾向于哪一种。

面向对象与函数式编程

面向对象

面向对象编程 以下统称 OOP

面向对象与函数式编程

主要代表的语言有:C++、Java、C#、VB、.Net 等

基本特征是:抽象、封装、继承、多态。

解释

抽象:把事物公共的属性和行为抽象(提取)出来,形成一个物理模型(可公用的模板),比方说小狗,他的抽象类就都是狗(狗妈妈)生的,四条腿,有耳朵,鼻子,眼睛等,但具体到你是黑狗、白狗、斑点狗等还得从品种来具体说明。

面向对象与函数式编程

封装:就是将类(方法)的属性包装起来,不让外界轻易知道它内部的具体实现;只提供对外接口供你调用;好处可以增强模块的独立性;如设置属性或方法的访问权限(private、protected、public、默认)。

继承:就是从父类把它的有用的东西拿过来自己用,不用在自己去实现了,还可以基于已经存在的类构造一个新类;继承已经存在的类就可以复用这些类的方法和域,在此基础上,可以添加新的方法和域,从而扩充了类的功能。 (比如:新出生的斑点狗的眼睛、尾巴、耳朵、鼻子等可以从狗(狗妈妈)那里继承过来,不用自己实现,但是肤色可以在此基础上添加自己的肤色)

继承在 Java 中实现


   class spottedDog extends Dog {        }

类 spottedDog 继承了 Dog,Dog 类称为父类或基类,spottedDog 类称为子类或派生类。

面向对象与函数式编程

好处

继承的作用在于代码的复用,由于继承意味着父类的所有方法亦可在子类中使用,所以发给父类的消息亦可发给衍生类。

再比如下面代码中, Person 类中有一个 eat 方法,那么 Student 类中也会有这个方法,这意味着 Student 对象也是 Person 的一种类型。

   class Person {    public void eat() {    System.out.println("eat");    }        static void show(Person p) {    p.eat();    }    }    public class Student extends Person{    public static void main(String[] args) {    Student s = new Student();    Person.show(s); // (1)    }    }    

运行结果:eat

在 Person 中定义的 show 方法是用来接收 Person 句柄的,但是在 (1) 处接收的却是 Student 对象的引用。这是因为 Student 对象也是Person对象。在 show 方法中,传入的句柄 (对象的引用) 可以是 Person 对象以及 Person 的衍生类对象,这种将 Student 句柄转换成 Person 句柄的行为在 Java 称为上溯造型。

多态:一个对象变量可以指向多种实际类型的现象。

比如一个人,在不同场合下,有不同的身份,不同的状态;比如在家里,你是父母的孩子;在学校,你就是学生;在公司,你就是老板的员工等。

你还可以在接口定义一个 run() 方法,是什么在跑,汽车还是马?通过不同类的实现来表示相似的逻辑。

面向对象与函数式编程

扩展

重载和重写(覆盖)的区别:

重载:相同的方法名,不同的实现机制(通过传入不同个数或类型的参数)。当程序运行过程中自己去判断到底该调用谁。比方说打人,那么多人,当你打起群架来,该打谁就打谁,事前你也不知道。

重写:从父类继承而来的方法不能满足需要的情况下,可以将此方法的逻辑在子类中重新实现。我们最常用的就是重写 toString() 方法了。

缺点:那些为了 OOP 而去 OOP 的傻子。

函数式

函数式编程 以下统称 FP

什么是函数式编程?

维基百科:In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data.

翻译:函数式编程是一种编程模型,它将计算机运算看做是数学中函数的计算,主要特点是将计算过程分解成多个可复用的函数,并且避免了状态以及变量的概念。

主要代表的语言有:Erlang、OCaml,Haskell、Scala 等

基本特征是:不可变数据、first class functions、尾递归优化。

下面废话几句,可能有点跑题

正如近几年大数据的热度居高不下,而在 Java 中它有一个名词叫 hadoop,其中的编程模型就是 MapReduce。

MapReduce??听起来挺高大上,它甚至对于一些人来说是可怕的,因为这些函数要求使用一种完全不同的方式来思考如何查询和排序数据,其实聪明的你一眼就爱看出来了,其实你可以理解成 : MapReduce = map + reduce。

map 就是键映射值的对象,也就是我们常说的 key - value。

reduce 人们常把它称为归约函数,我称之为精简函数(可能更合理),顾名思义,就是让我们在理解数据的基础上,找寻其主要的特征,在保证数据原貌的前提下,最大限度的去精简数据。

那么 MapReduce 相对传统的编程模型要解决的是什么呢?

比如,有块玉米地,里面有十排玉米,我想统计下这块玉米地所有玉米的总数。

一般情况下都会一个个数,当然,这是最笨的方法,那用更快的方式怎么做。

如果按照 MapReduce 的思想会这么做:

  • 找十个工人,每人数一排。

  • 将每个人的结果求和。

具体实现一下:

定义一下方法,

   map(); //对数据执行分批并行操作        reduce();//对操作所有返回值求和      cornCount();//每个工人数一排玉米        cornSum();//求和

精简一下代码,求十排玉米的操作可表示为:

   map(cornCount()).reduce(cornSum());


面向对象与函数式编程

有经验的童鞋,可能觉得我用其他方法也能实现或者使用 C++ 操作 IO 都可能比你快,别急,接着看。

这时候,老板又来了一个需求,要求数出甜玉米的数量,还得知道那一排的玉米数量最多。

解决方法:

   cornSweetCount();//数甜玉米的方法    map(cornSweetCount()).reduce(cornSum())//求得所有甜玉米的数量    max();//数甜玉米的方法      map(cornCount()).reduce(max())//那一排的玉米数量最多


面向对象与函数式编程

其实从上面的例子不难看出,FP 其实是将业务逻辑细化,抽象,封装成一个个功能函数,并借助语言自带的高阶函数 API,将整个业务流程转化为负责不同功能的函数并相互之间调用。

在函数式的世界里会这么处理:

  • 函数->行为

  • 值->属性

缺点:学习成本高,人在阅读代码时,是过程式的,FP 往往难于让其他人通读你的代码。

面向对象与函数式编程

我的看法

不论是面向对象编程还是函数式编程,如果你走了极端,那都是错误的;面向对象编程的极端是一切都是对象(纯面向对象);函数式编程的极端是纯函数式编程语言。

所以 FP 和 OOP 并不互相排斥,这两种编程范式一个抽象过程、一个抽象数据,正好是相辅相成的。

前者擅长描述是什么,而后者擅长描述如何做;FP 抽象出函数,OOP 聚合数据,很完美。

FP 是一整套大理论,其中是有层次的,FP 提升系统里函数的纯度,setup 和 teardown 虽有帮助,但还是增加了测试的难度,你要是不接受那些高级的部分,你就使用 map,reduce, throttle,debounce 就好了。

FP 也谈不上高大上,当你用 forEach 和 map 这样的 API 的时候你就在用 FP 了

纯 FP 无共享状态,程序运行时不改变外部状态,函数无副作用,相同输入永远相同输出,调用顺序时序无关;也就是说已知输入和输出任何函数就可以用它的返回值代替它本身。

OOP 要操作共享状态比如对象属性,所以是有时序的,先调用a方法再调用b方法,即使输入参数完全相同,结果也可能截然不同,因为 OOP 有时间维,所以出某些 bug 的时候需要从程序运行过程去找原因,查看一些变量的变化历史,逐步排查;

而 FP 没有时间维,所以只需要一个局部一个局部,一块一块地找问题,OOP 的(bug)事件会随时间而扩散,最后 crash 了整个世界,而 FP 天然是隔离的,一块空间坏了,问题通常只会局限在一个小区域中。

OOP 就像创建了一些工人,他们有自己高度复用的能力(成员方法),FP 就是一个业务流程,比如装配手机,相辅相成才是最好的;没有必选可选之分,如果硬要说占比,那肯定是业务流程占比多。

面向对象与函数式编程

抽象能力越高的模型往往越不自然,从常规编程和人类思维来说,这一点来说 OOP 反而更自然;OOP 是真实世界到程序世界的自然映射,FP 是真实世界经过数学抽象后才到程序世界的,是数学的映射,数学是强大的抽象工具。

而近几年大数据和云计算的兴起,编程方式在大数据处理领域演化成:算法+数据结构->函数+高阶函数+数据;而大数据处理往往使用函数式编程的方式更为合适,需要借助类似 MapReduce 这样的高阶函数去处理大量的数据结构,更加方便,这也是为什么函数式编程再次火起来的原因,正如马云说的那样,” 人类正从IT时代走向DT时代 “。

所以当你要抽象数据类型,请用 OOP,当你要抽象函数,请用 FP。

面向对象与函数式编程

福利时间

由上海最大的高端技术社群TopGeek和汇智Tek联合主办的 

本届大会主题为: “系统架构的迭代与创新”。随着云计算、分布式计算等技术变得越来越流行,在大数据、人工智能的新挑战下,许多系统架构都在不断演化、迭代,也有很多创新的架构设计方法如微服务的出现。重点基于案例来讲述如何设计好的架构解决开发及运维的效率问题。如何协调架构的核心原则、运行、集成、逻辑、部署等。如何提升架构师的领悟、领域、领袖能力。

门票有限,感兴趣的小伙伴请点击 查看原文 或者转发给程序猿的小伙伴们~

面向对象与函数式编程
面向对象与函数式编程

TopGeek 干货制造者


点开 阅读原文 了解详情,立即报名~

以上是关于面向对象与函数式编程的主要内容,如果未能解决你的问题,请参考以下文章

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

无状态面向对象编程与函数式编程?

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

面向对象与函数式编程

函数式范式与面向对象范式比较 — 以词频统计为例

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