声明式编程 (Declarative Programming)#
声明式编程是一种编程范式,它侧重于描述程序的目标(What to do),而不是详细规定实现目标的步骤(How to do)。这与传统的命令式编程(Imperative Programming)形成鲜明对比。
1. 核心思想#
- 抽象控制流:开发者不需要手动编写循环、状态变更和底层跳转。
- 状态不可变性:通常尽量减少或消除副作用。
- 幂等性:多次执行相同的声明,结果应当是一致的。
2. 常见的声明式子范式#
声明式编程是一个伞形概念(Umbrella term),它包含几个重要的子领域:
2.1 函数式编程 (Functional Programming)#
通过数学函数的求值来计算,避免状态改变和可变数据。
深入阅读:[[函数式编程 / index]]
2.2 逻辑编程 (Logic Programming)#
基于形式逻辑。程序是一组逻辑语句(规则和事实),由执行引擎通过推理得出结果。
- 代表语言:Prolog。
2.3 领域特定声明 (DSL)#
在特定领域内,使用声明式语法极大地提升了表达力。
- 数据查询:SQL(描述需要什么数据,而不是如何遍历 B-Tree)、GraphQL。
- UI 描述:HTML / CSS,现代前端的 React JSX, Vue Template, SwiftUI, Flutter (Widget tree)。UI 被视为状态的映射:
UI = f(state)。 - 配置即代码 (Infrastructure as Code):K8s YAML, Terraform。描述期望的最终系统状态,由 Operator / 引擎 去 reconcile(调和)达到该状态。
3. 命令式 vs 声明式 对比#
| 维度 | 命令式 (Imperative) | 声明式 (Declarative) |
|---|---|---|
| 关注点 | 怎么做 (How) | 做什么 (What) |
| 状态管理 | 手动修改变量状态 | 尽量无状态,或交由引擎管理 |
| 代码量 | 较长,包含大量控制流语句 | 简洁,表达力强 |
| 可测试性 | 较难(依赖隐含状态) | 较容易(输入输出明确) |
| 底层实现 | 贴近硬件执行模型 (冯诺依曼架构) | 依赖强大的编译器 / 执行引擎将声明翻译为底层指令 |
4. 走向融合#
现代编程语言和框架往往不是纯粹的某一种范式,而是多范式的融合。即使是偏向命令式的语言(如 Java, C++),也越来越多地引入声明式特性(如 Stream API, LINQ)。日常业务开发中,最理想的状态往往是:核心业务逻辑用函数式 / 声明式表达,而底层性能敏感或副作用重的部分用命令式实现。