编程范式
“普通的工程师堆砌代码,优秀的工程师优化代码,卓越的工程师简化代码”。
如何写出优雅整洁的代码,不仅是一门学问,也是软件工程的重要一环。在上一节中,我们简单介绍了响应式编程的编程范式,本节我们进一步从开发者的视角、系统的性能、满足用户需求等方面讨论不同编程范式的使用场景和特性优势。
编程范式,又称为编程模型,泛指软件编程过程中使用的编程风格,一般不同的编程范式具有不同的语法特性和差异。目前软件开发技术中常用的典型编程范式有以下几种。
- 命令式编程:定义处理事情的逻辑+实现处理事情的方法。
- 声明式编程:定义处理事情的逻辑框架。
- 函数式编程:定义处理事情的逻辑+通过函数实现基本功能。
- 面向对象编程。
因为每一个编程范式都有很长的发展历史,在编程语言支持上有不同的标准、组织和语法规范等,本节的目的是希望通过对这些编程范式的介绍,可以帮助我们更好地理解响应式编程范式。
命令式(指令式)编程
命令式编程是非常传统的软件编程方式,命令式编程由不同的逻辑执行步骤组成,通过一步步指令的执行达到业务逻辑的推进,这种方式也称为过程式编程。命令式编程的执行过程非常符合计算机的执行步骤。C语言是命令式编程的典型代表,它更关注的是机器域底层的内存、指令计算、输入输出。在C语言中,我们经常看到大段的过程式指令、各种if/else/for等控制语句、表达式、数据变量的操作、赋值等指令,这种纯指令开发方式要求开发者对计算机的底层工作原理有非常深刻的理解,而且一个指令出现偏差往往会产生不可预知的错误。同时,命令式编程模式的运维也是难度非常高的。
命令式编程的主要思想是关注计算机执行的步骤:
int a = 1;
int b = 2;
int c = a + b;
面向对象编程
面向对象编程可以说是编程领域的一个分水岭,开启了高级程序语言在软件开发上的统治阶段。面向对象编程从问题域出发,将封装、继承、多态的语言特性映射到我们的现实世界。在面向对象编程里,业务问题被抽象成类、接口模板,数据和行为被统一封装在对象内部,作为程序的基本组成单元。面向对象编程范式在提升软件重用性、灵活性和扩展性上比过程式编程更进一步,C++、Java作为面向对象编程语言的代表,屏蔽了机器底层的内存管理和机器域的管理细节。而面向对象编程虽然有较高的开发效率,但是降低了代码的运行效率,这也限制了面向对象编程在性能要求苛刻场景下的应用。
声明式编程
声明式编程受当前“约定优于配置”理念的影响,在软件编程开发领域中被大量应用。声明式编程范式的好处是可以通过声明的方式实现业务逻辑,不需要陷入底层具体的业务逻辑实现细节。声明式编程范式关注的焦点不是采用什么算法或者逻辑来解决问题,而是描述、声明解决的问题是什么。当你的代码匹配预先设定好规则,业务逻辑就会被自动触发执行。
很多标记性语言,如HTML、XML、XSLT,就遵循声明式编程范式,而Spring Boot基于注解方式的编程模型也是声明式编程的一个代表。
Spring框架依赖AOP和IoC编程思想降低了开发者对底层逻辑业务细节的了解程度。例如在Spring Boot中,通过@Transactional注解可以声明一个方法具备事务性的操作,当异常发生时,事务会自动回滚,保证业务逻辑的正常和数据一致性。发生在@Transactional注解背后的实现细节,开发者可以不去关心。
数据结构的形式来表达程序执行的逻辑:
SELECT * FROM collection WHERE num > 1;
函数式编程
在函数式编程范式中,函数无疑是一等公民,函数式编程最具魅力或者最重要的特性就是不可变性。它的不可变性表现在函数式编程表达式的执行结果,只取决于传入函数的参数序列,不受数据状态变化的影响。
函数式编程中的Lambda在Java 8中被引入,可以看成是两个类型之间的关系:一个输入类型和一个输出类型。Lambda演算就是给Lambda表达式一个输入类型的值,它就可以得到一个输出类型的值。
这个计算过程也是函数式代码对映射的描述,因为函数式代码的抽象程度非常高,所以也意味着函数式代码有更好的复用性。
函数式编程和命令式编程相比,更加关注消息或者数据的传递,而不像命令式编程,关注的是指令控制流。共享数据的状态在多线程环境下会存在资源竞争的情况,往往我们需要把额外的精力投入到冲突地解决、数据状态的维护中。而函数的不可变性保证了数据在传递处理过程中不会被篡改,也不需要依赖外部的锁资源或者状态来维护并发。所以函数式编程在多核处理器中具有天然的并发性,可以最大化地利用物理资源实现并行处理功能。
目前,在JVM体系中,已经出现了越来越多函数式编程范式的语言,例如Scala、Groovy、Clojure等。在当前计算机多核、数据优先、高性能的诉求下,函数式编程具有更广阔的发展前景和未来。然而有利总会有弊,函数式编程的语法相比面向对象编程更晦涩,在大规模工程化的协调配合中,还是需要我们去权衡利弊。因为无论哪种语言范式,本质上都是工具,最终目的都是为业务服务。
强调函数的计算比指令的计算更重要;与过程化编程相比,其中函数的计算可以随时调用:
List<Number> results = collection.stream()
.filter(n -> n > 5)
.collect(Collectors.toList());
转载自:
作者:東風谷早苗
链接:从架构师的角度带你把“响应式编程”给一次性搞明白,果然绝绝子
来自:知乎
作者:不学会Ⅳ
链接:编程范式-命令式编程、声明式编程、函数式编程
来自:CSDN