共四种编程模式,没有优劣,某一种或几种也不是银弹,也不存在鄙视链,只有适合的场景。但是在某种场景下选用特定的模式对代码会带来更好的可读性、可维护性和减少代码出错的概率,故值得我们去学习他们的不同之处。
过程式编程
过程式编程即『Procedural Paradigm』用一系列流程去完成任务,比如 VBScript 中的 procedure,没有返回值,存在副作用。
举例
VB 中的调用(Procedures)通常是为了组织代码和复用代码,分为函数(Function Procedures)调用和过程(Sub Procedures)调用。
二者的区别是函数有返回值,过程无返回值,有副作用,因为就是通过副作用达到其目的。
Sub outputMessage()
document.write("Welcome")
End Sub
该例子,调用了 document.write("Welcome")
,对 document 产生了『副作用』。
函数式编程
『Functional Paradigm』用一系列函数去完成任务,有返回值,函数一般没有副作用,即入参决定出参,且单测友好。
举例
第一个例子还是来自 VBScript
Function findArea(radius)
const pi=3.14
area = pi*radius*radius
findArea = area
End Function
计算面积函数返回面积,有返回值,无副作用,输入决定输出,相同的入参无用调用多少次,输出都是一样的。
函数式编程的另一个特点是函数可以当做参数,以 ramda.js#map 为例
const double = x => x * 2;
R.map(double, [1, 2, 3]); //=> [2, 4, 6]
PlainJS
const double = x => x * 2;
[1, 2, 3].map(double); //=> [2, 4, 6]
命令式编程
『Imperative Paradigm』强调实现细节,focus on How not What
举例
比如用 for 循环实现累加,我们会关注诸多实现细节,需要遍历所有项,需要关注遍历起始点,需要小心翼翼不能越界,
index++ 还可以多种写法等诸多细节,最后才是将其加起来。我们的目标『加起来』被淹没在重重细节中。
let sum = 0;
const users = [{ age: 18 }, { age: 28 }, { age: 38 }];
for (let index = 0; index < users.length; index++) {
const user = users[index];
sum += user.age;
}
声明式编程
『Declarative Paradigm』只声明目标不指定细节,focus on What not How
举例
使用声明式编程,我们更多关注在我们的目标,我们要什么,细节统统托管给库或更底层。
例一:mysql 实现累计
mysql 其实就是声明式编程的最佳范例。
select sum(age) from user where gender = male
翻译成中文『求 user 表中所有男性的年龄和』,关注点直驱目标『去和 sum(age)
』,没有啰嗦的实现细节。
例二:reduce 实现累计
用 reduce 实现累加,我们关注点在做『累加』即 acc + num
,这就是我们的目标,代码通常更简洁,因为无需遍历,也没有中间变量。
const users = [{ age: 18 }, { age: 28 }, { age: 38 }];
users.reduce((acc, user) => acc + user.age, 0);
声明式编程因为隐藏了细节,底层的实现会随着架构的优化不断优化,也就是同一份代码随着时间变化,速度将越来越快。以 java 的函数式编程为例。串行写法如下:
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int result = users.stream()
.reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
assertThat(result).isEqualTo(65);
同样只用关注累加 Integer::sum
我们甚至无需实现加法这个函数。
并发只需将 stream
改成 parallelStream
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
- int result = users.stream()
+ int result = users.parallelStream()
.reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
assertThat(result).isEqualTo(65);
就可以享受到多核带来的额外红利。
总结
声明式编程比命令式抽象层次更高。没有绝对的谁好谁好,但一定要用对场景。
-
声明式编程通常有框架或库辅助,解决通用的业务问题够用了,故日常开发中我们应该鼓励使用声明式编程模式
-
命令式编程通常在我们实现某种算法或实现一个框架或库需要,故日常开发我们应该尽量避免,因为其关注点分散,不容易阅读,而且细节多中间变量多意味着出错概率更大
-
函数式编程是声明式的子集。
-
过程式编程是命令式的子集。
我们初学代码的进化过程一般是
-
过程式到函数式
-
命令式到声明式
参考
- The Differences Between Procedural, Functional, Imperative, and Declarative Programming Paradigms
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!