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

面向对象是什么

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

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

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

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

函数式是什么

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

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

纯函数是不能有内部状态、也不能依赖上下文的,但确实有一些数据是在上下文中,这时需要再包一层函数,叫做Monad,而应用具体函数到这个被包裹的值得函数叫做Functor。

复用性很高的纯函数,根据具体逻辑的需求进行组合,比如串行的调用(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的)会用函数式,比如科学计算。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,916评论 2 89
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,100评论 0 6
  • 记得以前,大概大三以前吧。 我是一个不在乎自己时间的人,倒不是不知道时间的宝贵,而是不知道怎么利用自己的时间,不知...
    框框阅读 224评论 2 1
  • 前天下班回家,车子又跟别人擦到了。那时离家还有半小时,眼看就可以吃饭,躺床上休息了…… 还得打122,等交警来磨叽...
    471503Liwufeng阅读 515评论 0 0