不同维度的拆分:面向对象和函数式的区别

栏目: 后端 · 前端 · 发布时间: 5年前

内容简介:我们学习编程的时候,学完基础的语法就是学面向对象了吧。对于面向对象每个人都应该有一些理解,我这里讲一下我的理解。世间万事万物皆为对象,对象包括属性和行为。我们只需要把我们所关心的对象、属性、行为抽象出来就好了。比如兔子,如果我们关心的是龟兔赛跑的过程,那么我们只需要抽象出他速度、耐力等相关属性,他只需要跑和休息的方法,但如果我们是做生物研究的话,可能要抽象出毛发长度、耳朵形状等等属性,需要叫、跑、跳等方法。具体的封装粒度和形式与所关心的过程有关。不同的语言对于面向对象的实现不一样,有的是类式的,如Java

我们学习编程的时候,学完基础的语法就是学面向对象了吧。对于面向对象每个人都应该有一些理解,我这里讲一下我的理解。

世间万事万物皆为对象,对象包括属性和行为。我们只需要把我们所关心的对象、属性、行为抽象出来就好了。比如兔子,如果我们关心的是龟兔赛跑的过程,那么我们只需要抽象出他速度、耐力等相关属性,他只需要跑和休息的方法,但如果我们是做生物研究的话,可能要抽象出毛发长度、耳朵形状等等属性,需要叫、跑、跳等方法。具体的封装粒度和形式与所关心的过程有关。

不同的语言对于面向对象的实现不一样,有的是类式的,如 Java 、C++,有的是原型式,比如JavaScript,这只是不同的实现方式。思想和抽象的过程还是一样的。

面向对象的扩展方式是组合和继承,包括属性和方法两部分的复用。

函数式是什么

有个权威的定义是: 程序 = 逻辑 + 数据,逻辑部分可以拆分成一个个的函数,划分函数是为了复用和逻辑清晰,就像划分ui组件的目的一样。而如果一个函数与上下文耦合了,或者内部有一个可变的状态,那么它是很难复用的,因为你要先把他需要的环境配齐了,你才能去用。而没有内部状态和对外部环境依赖的函数是复用性很高的,叫做纯函数。纯函数和不纯的函数的区别就像绿色软件和需要安装的软件的区别一样,一个是依赖环境的,一个是对环境无依赖的。可能不那么准确,但可以直观感受下纯函数的好处。

纯函数因为对内部状态和外部环境都没有依赖,所以一个输入值,对应着唯一的输出值,所以也可以把它当成一个变量。而变量是可以进行算术、逻辑、比较等运算的,对应到纯函数也就有了算术运算函数、逻辑运算函数、比较运算函数等。

复用性很高的纯函数,根据具体逻辑的需求进行组合,比如串行的调用(pipe、compose),来完成具体的过程,组合需要接口统一,就像机械零件一样,所以统一成一个参数的比较好组合,函数参数归一化叫做currify。通过组合一系列的单个函数,完成不同逻辑过程,这就叫函数式。数据最后传入组合好的函数。

如下就是一个函数式的例子,通过组合把一系列过程封装到一个函数内,然后把数据传入这个函数就能完成整个过程。就像水流过管道一样,更直观点的感受可以说是先搭好了多米诺骨牌,然后把第一张骨牌推倒。这就是函数式的形式:组合好了函数管道,数据最后传入。

// 提取 tasks 属性
var SelectTasks = R.prop('tasks');

// 过滤出指定的用户
var filterMember = member => R.filter(
  R.propEq('username', member)
);

// 排除已经完成的任务
var excludeCompletedTasks = R.reject(R.propEq('complete', true));

// 选取指定属性
var selectFields = R.map(
  R.pick(['id', 'dueDate', 'title', 'priority'])
);

// 按照到期日期排序
var sortByDueDate = R.sortBy(R.prop('dueDate'));

// 合成函数
var getIncompleteTaskSummaries = function(membername) {
  return fetchData().then(
    R.pipe(
      SelectTasks,
      filterMember(membername),
      excludeCompletedTasks,
      selectFields,
      sortByDueDate,
    )
  );
};
复制代码

面向对象和函数式的区别是什么

面向对象是比较常见的思路,而函数式也是一种编程的思路,或者说这是两种编程范式。这两者的关系其实我们身边也能找到对应的。

比如目录结构的划分可以有两种维度,一种是先按代码功能划分再按业务模块划分:

components
   user-login
   goods-list
pages
    user-login
    goods-list
store
   user-login
    goods-list
utils
assets
复制代码

一种是先按业务模块划分再按代码功能划分:

user-login
    components
    pages
    store
    assets
    utils
goods-list
    components
     pages
    store
    assets
    utils
复制代码

这两种方式哪种更好呢,其实需要看具体情况,如果业务模块特别多,每个模块差别可能比较大,那么第二种方式更好,如果业务模块比较少,且基本都是一样的,那么第一种方式比较好。

这其实就和函数式与面向对象的区别一样,程序 = 数据 + 逻辑, 面向对象就像第二种方式,把数据和逻辑封装到了一起,作为整体来复用和组合,而函数式则是把数据和逻辑分开,逻辑部分通过函数的组合来复用,之后再传入数据。

所以,函数式和面向对象也就没有哪个更好一说,如果是数据和逻辑的关系耦合紧密,那么还是封装成对象来复用更好,如果逻辑比较独立,那么逻辑部分用函数式来拆分和复用更好。这只是两种划分维度。

一般来说游戏中用面向对象比较多,因为他们涉及到的对象都是数据和方法耦合特别紧密的,比如子弹,你如果用函数式的方式把子弹的数据和子弹运动的函数分开,也没啥意义,一是因为子弹运动的函数对别的模块来说没有多大的复用和组合的价值,二是分开这两部分可能会导致程序很难理解。后端的代码也一般是面向对象比较多,但是一般后端的Model层都是贫血模型,就是操作数据的逻辑和数据实体类是分开封装的,我觉得这样的话用函数式可能会更好。函数式用的最多的领域还是科学计算领域,因为这些计算过程是完全的与数据无关的,也叫pointfree的。

总结

面向对象是以所研究的业务实体为角度来抽象和封装对应的属性和方法,以实体的方式来组合和复用,组合方式有继承、组合等。而函数式是另一个维度的划分,把数据和逻辑分开,对逻辑部分划分成容易复用的纯函数,同时提供一系列的算术、逻辑、关系运算函数,之后通过函数组合来复用。

这两种方式只是不同的划分角度,就像目录结构的划分一样。一般数据和逻辑耦合很高的业务过程会用面向对象,比如游戏开发,而逻辑和数据关系不紧密的(pointfree的)会用函数式,比如科学计算。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Parsing Techniques

Parsing Techniques

Dick Grune、Ceriel J.H. Jacobs / Springer / 2010-2-12 / USD 109.00

This second edition of Grune and Jacobs' brilliant work presents new developments and discoveries that have been made in the field. Parsing, also referred to as syntax analysis, has been and continues......一起来看看 《Parsing Techniques》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码