当前位置: 首页 > 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.dtcms.com/a/305781.html

相关文章:

  • 关于神经网络CNN的搭建过程以及图像卷积的实现过程学习
  • OSS-服务端签名Web端直传+STS获取临时凭证+POST签名v4版本开发过程中的细节
  • 修改Windows鼠标滚轮方向
  • 《计算机组成原理与汇编语言程序设计》实验报告六 存储器实验
  • mangoDB面试题及详细答案 117道(071-095)
  • LeetCode 160:相交链表
  • 使用es实现全文检索并且高亮显示
  • 利用SQL文件上传注入植入WebShell
  • Linux->动静态库
  • UniSeg3D:A Unified Framework for 3D Scene Understanding
  • 如何读懂 火山方舟 API 部分的内容
  • yolo8+阿里千问图片理解(华为简易版小艺看世界)
  • PostgreSQL 与 Oracle 数据库字段类型的详细对比
  • CSS 工作原理
  • Qt知识点2『Ubuntu24.04.2安装Qt5.12.9各种报错』
  • git报failed to connect to github.com port 443 after 21064
  • 项目文档太多、太混乱怎么解决
  • Qt 在 ARM 平台上的移植与优化
  • 中国高铁从追赶到领跑的破壁之路
  • 15.11 单卡训练770M参数模型!DeepSpeed ZeRO-3实战:RTX 4090显存直降6.8GB
  • 接口自动化测试
  • 深入剖析 StarRocks 与 Hive 的区别、使用场景及协同方案实践
  • 【IDEA】JavaWeb自定义servlet模板
  • 手机定位和IP属地究竟有何不同
  • 【Lambda】flatMap使用案例
  • Redis 面试全解析:从数据结构到集群架构(含实战解决方案)
  • 《Java 程序设计》第 10 章 - 接口与 Lambda 表达式
  • #C语言——学习攻略:深挖指针路线(四续)——函数指针数组--转移表
  • 【支持Ubuntu22】Ambari3.0.0+Bigtop3.2.0——Step4—时间同步(Chrony)
  • 从0开始学习R语言--Day62--RE插补