当前位置: 首页 > news >正文

Nestjs框架: 关于 OOP / FP / FRP 编程

概述

  • 在软件开发过程中,不同的编程范式为我们提供了多样化的思维方式与实现路径
  • 它们不仅影响着代码的结构和逻辑组织方式,
  • 也深刻影响着项目的可维护性、可扩展性以及团队协作效率

什么是 OOP、FP 和 FRP?


首先从三个术语的含义入手

1 )OOP(Object-Oriented Programming)

  • 即面向对象编程,是一种将现实世界中的事物抽象为“对象”的编程范式
  • 每个对象拥有自己的属性和方法,通过类(class)来定义这些对象的共同特征

2 )FP(Functional Programming)

  • 即函数式编程,强调“函数”作为程序的基本构建单元
  • 主张将逻辑封装在纯函数中,注重数据变换而非状态变化

3 )FRP(Functional Reactive Programming)

  • 即函数式响应式编程,是函数式编程与响应式编程的结合体
  • 适用于处理异步事件流,常用于 UI 编程、事件驱动等场景
  • 这三种编程范式并非彼此对立,而是适用于不同场景的编程风格
  • 它们分别代表了软件开发中三种重要的抽象方式:对象抽象、函数抽象与事件流抽象

OOP 与 FP 的核心区别与实现对比


以一个实际的前端登录注册功能为例,来对比 OOP 和 FP 两种范式的实现方式

1 )通用页面结构

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>FP&FRP</title><script src="./index.js" defer></script></head><body><div class="container-sm pt-4"><form class="col-4" id="login-form"><div class="mb-3"><label for="username" class="form-label">用户名:</label><inputtype="text"class="form-control"name="username"id="username"aria-describedby="username-help"/><div id="username-help" class="form-text"></div></div><div class="mb-3"><label for="password" class="form-label">密码</label><inputtype="password"name="password"class="form-control"id="password"/><div id="password-help" class="form-text"></div></div><div class="mb-3 form-check"><input type="checkbox" class="form-check-input" id="remember" /><label class="form-check-label" for="remember">记住我</label></div><button type="submit" class="btn btn-primary" id="btn">注册或登录</button></form></div></body>
</html>

2 )面向过程编程:传统逻辑结构

// 获取form对象
// 当用户点击提交按钮时,获取用户输入的值
// 校验用户输入的值
// 如果校验通过,模拟发送请求提交表单
const form = document.getElementById('login-form');
const username = document.getElementById('username');
const password = document.getElementById('password');function submitHandler(evt) {evt.preventDefault();const usernameValue = username.value;const passwordValue = password.value;if (usernameValue.trim().length === 0) {alert('用户名不能为空');return;}if (passwordValue.trim().length < 6) {alert('密码长度不能小于6位');return;}const user = {username: usernameValue,password: passwordValue,};console.log(user);console.log('用户' + user.username + '登录成功');
}form.addEventListener('submit', submitHandler);
  • 在传统的面向过程编程中,我们通常会按照“顺序执行、逐步处理”的方式去实现功能。
  • 例如:
    • 首先完成页面结构与样式;
    • 然后绑定表单提交事件;
    • 接着读取输入框的值;
    • 再进行输入校验;
    • 最后将数据打印或发送请求。
  • 这样的逻辑虽然直观,但随着功能的复杂度增加,会导致代码冗长、不易维护、逻辑耦合度高

3 ) 函数式编程(FP)的核心实现思路

// 获取form对象
// 当用户点击提交按钮时,获取用户输入的值
// 校验用户输入的值
// 如果校验通过,模拟发送请求提交表单
const REQUIRED = 'REQUIRED';
const MIN_LENGTH = 'MIN_LENGTH';// 函数式编程
function validate(value, flag, validatorValue) {if (flag === REQUIRED) {return value.trim().length > 0;}if (flag === MIN_LENGTH) {return value.trim().length > validatorValue;}
}function getUserInput(inputId) {return document.getElementById(inputId).value;
}function createUser(username, password) {if (!validate(username, REQUIRED) || !validate(password, MIN_LENGTH, 6)) {// alert -> 副作用 -> 依赖外部环境(HTTP请求、修改DOM等操作了外部环境)// -> 在函数式编程中,尽量要避免出现副作用throw new Error('用户名或者密码不符合要求');}return {username,password,};
}function greet(user) {console.log('用户' + user.username + '登录成功');
}function submitHandler(evt) {evt.preventDefault();const usernameValue = getUserInput('username');const passwordValue = getUserInput('password');try {const user = createUser(usernameValue, passwordValue);console.log(user);greet(user);} catch (error) {alert(error.message);}
}function createForm(formId, handler) {const form = document.getElementById(formId);form.addEventListener('submit', handler);
}createForm('login-form', submitHandler);

在函数式编程中,我们通过函数的组合与复用来构建逻辑:

  • 定义一个 createForm(formID, handler) 函数,用于绑定表单提交事件;
  • 定义 submitHandler 函数,用于处理提交后的逻辑;
  • 定义 getInputValues 函数,用于获取输入框的值;
  • 定义 validate 函数,用于校验输入是否合法;
  • 定义 createUser 函数,用于创建用户对象并返回;
  • 最后通过 console.log 打印成功信息。

函数式编程的核心特征包括:

  • 纯函数:对于相同的输入,总是返回相同的输出,没有副作用;
  • 可组合性:函数之间可以相互调用、组合,形成清晰的数据流;
  • 高复用性:函数可以被多个模块复用,提升代码维护效率;
  • 可测试性强:由于函数是独立的,单元测试更容易实现。

函数式编程非常适合处理数据变换、逻辑解耦和异步流程控制

4 )面向对象编程(OOP)的核心实现思路


在面向对象编程中,我们通过类和对象来组织代码结构:

// 获取form对象
// 当用户点击提交按钮时,获取用户输入的值
// 校验用户输入的值
// 如果校验通过,模拟发送请求提交表单
class Validator {static REQUIRED = 'REQUIRED';static MIN_LENGTH = 'MIN_LENGTH';static validate(value, flag, validatorValue) {if (flag === this.REQUIRED) {return value.trim().length > 0;}if (flag === this.MIN_LENGTH) {return value.trim().length > validatorValue;}}
}class User {constructor(username, password) {this.username = username;this.password = password;}greet() {console.log('用户' + this.username + '登录成功');}
}class UserInputForm {constructor() {this.form = document.getElementById('login-form');this.username = document.getElementById('username');this.password = document.getElementById('password');// 这里要注册第二个submitHandler为什么要使用bind// addEventListener的第二个参数是一个回调函数,回调函数中的this指向的是当前的DOM元素// 但是这里的this,需要指向的是UserInputForm,所以需要使用bind修改this的指向this.form.addEventListener('submit', this.submitHandler.bind(this));}submitHandler(evt) {evt.preventDefault();const usernameValue = this.username.value;const passwordValue = this.password.value;if (!Validator.validate(usernameValue, Validator.REQUIRED) ||!Validator.validate(passwordValue, Validator.MIN_LENGTH, 6)) {alert('用户名或者密码不符合要求');return;}const user = new User();user.username = usernameValue;user.password = passwordValue;console.log(user);user.greet();// console.log('用户' + user.username + '登录成功');}
}new UserInputForm();
  • 我们定义了三个类:ValidatorUserLoginForm
  • LoginForm 类负责绑定表单事件、读取输入、调用校验器、创建用户
  • User 类封装了用户的属性和行为(如 greet() 方法)
  • Validator 类提供静态方法 validate() 来完成输入校验

OOP 的三大核心特性是:

  • 封装性:将数据和操作封装在一个类中,增强模块化
  • 继承性:通过继承复用已有类的属性和方法
  • 多态性:同一方法在不同对象中有不同实现

面向对象编程更适合建模现实世界的结构、处理复杂的业务逻辑与状态管理

5 )函数式响应式编程(FRP)

const btn = document.getElementById('btn');function inputHandler(evt) {if (username.value.trim().length === 0 || password.value.trim().length < 6) {btn.disabled = true;return;}btn.disabled = false;
}
username.addEventListener('input', inputHandler);
password.addEventListener('input', inputHandler);
  • 虽然在本次示例中没有详细展开 FRP,但我们可以简要介绍其核心思想与适用场景

什么是函数式响应式编程?

  • 函数式响应式编程(FRP)是函数式编程与响应式编程的结合,强调对事件流进行函数式处理
  • 它通过将事件流视为可组合、变换的数据流,实现复杂的异步逻辑处理。

典型应用场景

  • 表单实时校验:当用户输入时,自动判断输入是否合法,并动态修改按钮状态
  • 聊天推荐系统:点击拒绝推荐后,自动请求新数据并更新界面
  • 实时数据展示:如股票价格、天气数据等需要响应变化的场景

核心特点

  • 响应式处理事件流:将事件流视为可观测的数据流,进行函数式操作
  • 异步处理友好:天然适合处理异步、并发、事件驱动的场景
  • 依赖第三方库:如 RxJS、MobX、Vue 3 的响应式系统(Composition API)等
  • 发布-订阅模式:通过订阅事件流来响应数据变化,实现 UI 与状态的自动同步

OOP 与 FP 应该如何选择?


在实际开发中,OOP 和 FP 并非非此即彼,而是可以根据项目需求、团队习惯、技术栈等因素灵活选择

  • 若项目需要建模复杂业务逻辑、状态管理、类结构清晰,则更适合使用 OOP
  • 若项目更注重逻辑解耦、数据变换、可测试性与复用性,则更适合使用 FP
  • 若项目涉及大量异步事件、实时响应或复杂事件流处理,则可引入 FRP 或响应式编程框架

此外,现代前端框架(如 React、Vue)已经融合了多种范式的思想:

  • React 更偏向函数式编程,鼓励使用函数组件和 hooks
  • Vue 3 支持 Composition API,也更适合函数式风格
  • Angular 仍以 OOP 为主,但也在逐步引入响应式编程理念

编程范式之间的关系与发展趋势

编程范式核心思想关键特征适用场景
OOP(面向对象)抽象现实事物为对象封装、继承、多态复杂业务、状态管理
FP(函数式编程)函数为基本单元,强调纯函数不可变、无副作用、可组合数据处理、逻辑解耦
FRP(函数式响应式)响应事件流,函数式处理异步友好、流式处理实时响应、UI 变化
  • 未来的开发趋势是多范式融合,开发者应具备灵活选择与组合不同编程风格的能力
  • 理解 OOP、FP 和 FRP 的本质,有助于我们在不同的项目中做出更合适的技术选型
http://www.lryc.cn/news/605022.html

相关文章:

  • Map 集合
  • 高可靠液晶屏系统解决方案深度解析
  • AI 驱动的软件测试革新:框架、检测与优化实践
  • 原生C++实现信号与槽机制:原理详解
  • 如何选择GEO优化公司哪家好?
  • Apache FOP实践——pdf模板引擎
  • 推扫式和凝视型高光谱相机分别采用哪些分光方式?
  • MaxKB+MinerU:通过API实现PDF文档解析并存储至知识库
  • 梳理Ego-Planner模式下5通道、6通道与无人机模式的关系
  • Camera相机人脸识别系列专题分析之十九:MTK ISP6S平台FDNode传递三方FFD到APP流程解析
  • 不可变类字段修复建议
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘dash’问题
  • Python 程序设计讲义(43):组合数据类型——元组类型:元组的常用操作
  • WSL2搭建基于Docker的ESP32开发环境
  • 机器学习项目完整流程详解
  • 基于C-MTEB/CMedQAv2-rerankingv的Qwen3-1.7b模型微调-demo
  • Android基础(二)了解Android项目
  • 端侧大模型迎来“轻”革命!移远通信 × RWKV 打造“轻量AI大脑”
  • 单片机电路基础
  • 【NCS随笔】如何在hello_world添加蓝牙功能(一)
  • sqli-labs:Less-7关卡详细解析
  • 国内数据集成厂商有哪些?如何选择最适合的数据集成平台?
  • Qt 与物联网(IoT)开发
  • 【Linux】重生之从零开始学习运维之备份恢复
  • String模拟实现的补充说明
  • 第1课:向量与矩阵运算
  • QT中QTableView+Model+Delegate实现一个demo
  • 【ESP32设备通信】-LAN8720与ESP32集成
  • 如何设计一个站内消息系统:架构设计合集(八)
  • 订单识别技术原理及场景应用