内容简介:本文是要引入一个框架,从上到下的过程包括
本文是 状态管理框架 选型预研时看到油管上一个Talk的部分内容的总结和一些自己的思考。
要引入一个框架,从上到下的过程包括
- API的使用 (调用)
- API的设计 (接口)
- API的实现 (源码)
- API实现的是哪个思想 (原理)
状态管理框架 可追根溯源到函数式的本质特性上,所以有必要先搞清楚函数式为何物。
而一个“新”事物的流行往往会产生泡沫,所以总 是会把函数式当成 银弹 ,如同对待 区块链 , 人工智能 和 大数据 一样。在这里希望一方面把函数式的来龙去脉说清,另一方面戳破这些浮夸的 泡沫效应 ,让它回归到原有的价值。
函数式从何而来
函数式的历史可以追述到1930年代的{lambda calculus},函数式编程本质上就是对 λ演算 的一种实现。基本思想就是 只通过“变量”和“函数”两个元素来解决问题 。这个思想给函数式编程带来诸如 匿名函数 、 一等公民 、 柯里化 等概念。
我们所接触到的主流编程语言几乎都是 图灵机 的思想延续,可见这一分支一直是处于绝对统治地位。但随着现代语言越来越多的加入 λ演算 的特性,这两个思想最终产生了交集。
那么函数式思想为什么从一个小众的事物慢慢变成了显学了呢?那么我们看一下这个思想到底给软件工程注入了哪些新鲜血液。
图灵系语言的问题
有一种误解是学习函数式 要忘记掉你所学过的编程方式 ,但与其说引入函数式就是要用它 替代 面向对象 ,还不如说是对 面向对象 的程序进行 重构 ,毕竟两者各有优劣。
我们一开始满足某个业务写的 面向对象 代码可能是以下的样子,你可以把他看做一些页面,函数或是模块。
随时业务的变化,可能有些组件被删掉,或是新增了新的模块,也可能是模块间的调用/依赖关系有了变化。于是复杂度开始增大。
代码变成这个样子后,虽然表面上仍然可以使用,但是源码却已经 难以理解和维护 我们会发现难以理解的一个原因是: 这个系统一件事的成立,需要大量的前提! ++因为依赖太多++
图灵系的语言也有一样的困境,随着语言的迭代更新,逐渐加入了更多的限制:
- 比如 Ruby 用{protected method}表示一种函数让其只能被自己和子类所访问
- C++ 引入{friend function}来表示一个函数不是类的成员函数但是能访问类的私有成员
当一个概念越来越 难以理解 的时候,就到了一个改变的节点上。比如减少概念:Swift就没有protect关键字 [why];但更有效的思路是引入更加 简单 的 函数式 。
函数式的函数
数学家,和 程序员 一样,对概念的_封装_,_组合_有着巨大的需求。 例如英国数学家在一本著作中花了 379页 推导出 1+1=2
他们是怎么管理好这么多封装,最终能串联起来解决问题的呢? 可否把他们的经验拿来借鉴?
答案就是 数学函数
数学函数 是 输入集合到输出集合映射 。
而函数式语言的函数特性就是 数学函数
这和 面向对象 的函数可不一样,我们一般而言的 函数/方法 ,都是一些statement的集合。也就是说,他可以对外界环境进行改造 (比如网络请求,数据库请求),也可以完全没有输入和输出,更不用提说什么映射了。
重构1:加入纯函数
但其实要想借鉴过来也很简单,比如大多现代语言都引入了 闭包 , 一等公民 ,在此基础上只需要给日常所写的函数加一个 约束 ,就可以做到类似数学函数的效果。(加了这些约束的函数被称为 纯函数 ,或 引用透明 )这个约束就是: 没有副作用 (只能加工参数,输出结果,不能修改外界环境)
如果我们平时多写纯函数,问题就已经得到了一定的简化。
重构2:加入不可变特性 Immutable
纯函数 带来的一个好处就是 不可变 immutability ,因为 纯函数 只能处理输入,返回输出,那外界的状态就可以通过 拷贝 的方式传递进来,不用修改原来的值:
比如对于把x这个集合传入各种各样的函数内,x并不会改变。
这个好处不言而喻,不可变意味着线程安全,意味着不必因为一些bug去查看每一个可能产生的函数。
例如Swift就引入了这个特性,除了 class 都是 值类型 ,传递即拷贝,并通过 copy-on-write 实现按需拷贝,降低空间开销。
重构3:控制副作用
纯函数 不是一个褒义词,如同 副作用 不是一个贬义词一样。
我们程序员获得薪水的原因就是 编写程序通过写一些不纯函数来产生副作用 (例如改变数据库里的数据)
用户不关心代码,只关心你能带给他们什么样的 副作用 ,只有程序员才关心这个过程够不够优雅。
问题在于如何处理 副作用 ?
答案是 桥 ,换句话说就是一层封装,把真正要产生的 副作用 藏起来。调用 桥 只能通过一个 如何修改该值 的函数给它,由这层封装来帮你实现 副作用 。
如果是状态修改,有一种方式是:当有冲突发生的时候,会重新执行需要再次更新的函数。(类似数据库的transaction)
如果是修改外部环境,一般会把请求放到队列里,统一派发。
即使是函数式语言, 副作用 也是要做的,不然这个程序就毫无意义,只是我们把 副作用 和 纯函数 隔离了起来,让他们的影响在一个可控的范围内。
这种隐藏状态,通过传递函数修改状态的管理 副作用 的方式,就是我们下面要聊的状态管理思想。
总结,函数式带来的最大好处?
那就是并发!
共享全局状态是维护的噩梦,单纯的乱代码还不足以造成无法理解,可以通过清理最终理清,但如果是并发问题的代码,需要釜底抽薪的改造才可能把各种线程间的协作交接清楚。
即使我们不引入 状态管理框架 ,仅仅是让数组不可变,用Promise/RxSwift之类把异步的代码梳理好,也 至少 能让出现问题的线程拿到了不同版本的数据,由于数据间的隔离就不会有这边遍历那边修改导致的闪退。
如果在应用了Promise/RxSwift之外,引入了 状态管理框架 ,就意味着有了一个方便的途径,可以直接声明一种安全的共享状态,所有的修改都是统一控制的,不仅仅不会出错,还可以让每次修改都能有序的生效。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Python 拓展之特殊函数(lambda 函数,map 函数,filter 函数,reduce 函数)
- Python 函数调用&定义函数&函数参数
- python基础教程:函数,函数,函数,重要的事说三遍
- C++函数中那些不可以被声明为虚函数的函数
- 017.Python函数匿名函数
- 纯函数:函数式编程入门
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。