理解编程范式(前端角度)

编程范式(Programming Paradigms)是编程的一种风格或方法,它定义了代码的结构和组织方式。编程范式提供了不同的思考和解决问题的角度,影响着程序员如何编写代码。

常见的前端编程范式包括:

  • 命令式编程(Imperative Programming)
  • 声明式编程(Declarative Programming)
  • 函数式编程(Functional Programming)
  • 面向对象编程(Object-Oriented Programming)

命令式编程(Imperative Programming) - 关注"如何做"(How)

特点:关注"如何做"(How),核心思想是通过一系列明确的指令(如变量赋值、循环、条件判断)来改变程序的状态,逐步引导计算机完成任务。它强调 "过程" 和 "状态变化",就像给计算机一步步下达操作命令。

然后,看看下面的代码属于命令式编程么?

javascript 复制代码
const isEven = (number) => number % 2 === 0;
const square = (number) => number * number;
const add = (a, b) => a + b;
function sumOfEvenSquares(numbers) {
  // 声明变量保存中间状态(总和)
  let sum = 0;
  // 循环遍历数组,(明确的步骤:逐个检查元素,并进行处理)
  numbers.forEach((number) => {
    // 条件判断,筛选偶数
    if (isEven(number)) {
      // 修改状态(总和)
      sum += square(number);
    }
  });
  // 返回结果
  return sum;
}

// 使用
console.log(sumOfEvenSquares([1, 2, 3, 4, 5, 6])); // 56

答案:上面是命令式编程。

以前我粗浅的以为,看到forEach就是声明式编程,看到提取函数以为是函数式编程,其实还是命令式编程,因为sum在被显示的修改。

其整个流程依然是 "初始化 sum → 循环数组 → 逐个判断 → 累加偶数 → 返回结果"

重新梳理下命令式编程的特点:

  • 步骤化指令(关注步骤,明确每一步的执行过程)
  • 依赖显式状态修改(状态在显示的修改,比如sum在显示的被修改)
  • 控制流由开发者主导(开发者控制程序的执行流程,比如for循环、if判断等)

场景和优缺点

  • 适合场景:适合简单、步骤明确的逻辑的场景
  • 优势:直观、可控性强
  • 缺点:复杂逻辑下代码容易冗长(如多层嵌套循环)

类比炒西红柿炒鸡蛋

你手里有一份《番茄炒蛋盖浇饭步骤说明书》,严格按步骤执行:

  • 拿出 2 个番茄,洗净,切成小块(明确 "拿、洗、切" 的动作);
  • 拿出 2 个鸡蛋,打入碗中,用筷子搅拌均匀(明确 "打、搅" 的动作); 开火,锅烧热后倒入 2 勺油(明确 "开火、加热、倒油");
  • 倒入鸡蛋液,翻炒至凝固,盛出备用(明确 "倒、炒、盛");
  • 锅里再倒 1 勺油,放入番茄块,翻炒出汁(明确 "倒、放、炒");
  • 倒入炒好的鸡蛋,加 1 勺盐、半勺糖,翻炒均匀(明确 "倒、加、炒");
  • 拿出一碗米饭,盛在盘子里,把炒好的番茄炒蛋浇在米饭上(明确 "拿、盛、浇")。

你自己控制整个流程,自己把控每一步的执行过程。

但是注意,每个步骤有可能会涉及其他的范式。

声明式编程(Declarative Programming) - 关注"做什么"(What)

特点 :其实这个是相对于命令式编程来说的,命令式编程是关注"如何做"(How),描述具体的实现步骤,而声明式编程是关注"做什么"(What),开发者只需描述 "想要的结果 / 目标",而无需编写具体的执行步骤、控制流(循环、分支)或手动管理状态,具体的实现细节(如遍历、状态维护)由语言或框架自动完成。

看下同样的功能,使用声明式编程的代码:

javascript 复制代码
const isEven = (n) => n % 2 === 0;
const square = (n) => n * n;
const sum = (acc, curr) => acc + curr;

const sumOfEvenSquares = (numbers) =>
  numbers
    .filter(isEven) // 描述:筛选偶数(不关心如何遍历)
    .map(square) // 描述:计算平方(不关心如何处理)
    .reduce(sum, 0); // 描述:累加求和(不关心如何维护状态)

// 使用
console.log(sumOfEvenSquares([1, 2, 3, 4, 5, 6])); // 56

看着好像也是一步步的,但这些 "步骤" 是 "目标的分解",而非 "执行的指令"。

第一步:我需要"筛选出偶数"这个结果,而不是具体的如何遍历、如何判断偶数。 第二步:我需要"计算平方"这个结果,而不是具体的如何计算平方。 第三步:我需要"累加求和"这个结果,而不是具体的如何累加求和。

每一步都是对 "中间结果" 的描述,而非 "如何实现这个中间结果" 的指令。你不需要告诉计算机 "如何筛选偶数"(是否用 for 循环、forEach 还是其他方式),filter 内部已经封装了遍历逻辑。 同样,你不需要手动维护 "筛选后的数组""平方后的数组" 这些中间状态,它们由函数自动生成并传递。也就是底层的遍历和状态维护完全封装。

看下sql的例子加深理解:

sql 复制代码
-- 目标:查询"年龄大于18的用户姓名",不关心数据库如何检索
SELECT name FROM users WHERE age > 18;
-- 命令式思路会是:"打开数据库→遍历所有用户→判断年龄→收集姓名",而 SQL 直接描述结果。

场景和优缺点

  • 适合场景:数据查询、复杂计算逻辑
  • 优势:可读性高、可维护性强、抽象程度高
  • 缺点:可能产生中间数组,内存占用较大

注意,声明式是一个 "大范式",包含多个具体的子范式,覆盖不同场景,常见的子范式包括:

  • 函数式编程(FP):用纯函数组合描述计算,无副作用、不可变数据(如 JavaScript 的 filter+map+reduce、Haskell)。
  • 逻辑编程:通过 "事实 + 规则" 推导结果,而非步骤(如 Prolog)。
  • 数据查询语言:描述需要的数据,而非获取数据的过程(如 SQL、GraphQL)。
  • 响应式编程:基于数据流和变化传播处理异步(如 RxJS)。
  • 标记语言:描述 "内容结构",而非 "渲染步骤"(如 HTML、XML)。

这些子范式的共性是 "声明目标,不写步骤",差异是 "目标类型不同"(计算、推理、数据、异步、结构)。

类比去餐馆点炒西红柿炒鸡蛋

你去餐馆,直接跟服务员说:"我要一份番茄炒蛋盖浇饭,米饭要软硬适中,番茄要炒出汁,少盐少糖。" 你完全不用管:厨师是先炒鸡蛋还是先炒番茄、用多少油、炒多久 ------ 只需要告诉 "最终需求",厨师会自己处理所有步骤。

函数式编程(Functional Programming)- 函数

特点 :一种以 "函数" 为核心的声明式编程范式,其核心思想是将计算过程视为 "纯函数的组合",强调无副作用、不可变数据、函数是 "第一公民" 等特性,通过函数的嵌套和组合 来解决问题,而非通过修改状态执行步骤

注意,函数式编程是声明式编程的子范式,所以如果是函数式编程的,一定属于声明式编程。反过来不一定成立。

所以声明式编程里面的求和代码,也属于函数式编程。

函数式编程的核心原则

  • 纯函数(相同输入必产相同输出;不修改函数外部的任何状态(如全局变量、参数对象、DOM 等),也不依赖外部状态的变化)
  • 不可变数据(数据一旦创建就不可修改,只能通过创建新的数据来修改)
  • 函数是 "第一公民"(函数可以作为参数传递、可以作为返回值返回、可以作为变量赋值)

函数式编程的常见工具

  • 高阶函数(如 map、filter、reduce、flatMap等,用于组合数据处理逻辑)
  • 柯里化(currying,将多参数函数转化为一系列单参数函数的过程,便于复用和组合)
  • 函数组合(compose,将多个函数组合成一个函数,执行顺序从右到左或者从右到左)

场景和优缺点

  • 适合场景:适合数据处理、逻辑处理、函数组合的场景
  • 优势:代码可测试性强、易于并行化、函数可复用、减少 bug
  • 缺点:学习曲线陡峭、可能产生性能开销、不适合所有场景

拆解React的核心设计,加深函数式编程的理解

React并非 "纯函数式框架",而是选择性吸收了函数式编程(FP)的核心思想,并结合前端开发的实际场景(如 UI 状态管理、组件复用、副作用处理)进行落地。其核心目的是:通过 FP 的特性(纯函数、不可变数据、无副作用)解决前端开发的经典痛点(如状态混乱、组件复用复杂、调试困难),让代码更可预测、可维护。

从 React 的核心设计和实践出发,拆解它如何 "吸收 FP 思想",从而加深对函数式编程的理解。

用 "纯函数组件" 替代 "类组件"(React 16.8+ Hooks 时代)

函数式编程的核心是 "纯函数",React 把这个思想落地为 函数组件(Function Component)+ Hooks,替代了早期的类组件(Class Component)。

React 函数组件本质是一个 "输入 → 输出" 的纯函数:

  • 输入:props(父组件传递的参数)+ state(组件内部状态,通过 Hooks 管理);
  • 输出:UI 描述(JSX);
  • 无副作用(理想状态):组件本身只负责 "根据输入渲染 UI",不直接操作 DOM、不修改外部状态、不发起网络请求(这些都属于副作用,交给专门的 Hooks 处理)。
jsx 复制代码
// 纯函数组件:输入 props(name),输出 UI,无副作用
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

// 调用时,相同输入必然产生相同输出(可预测)
<Greeting name="小明" /> // 输出 <h1>Hello, 小明!</h1>
<Greeting name="小红" /> // 输出 <h1>Hello, 小红!</h1>

之前的:

jsx 复制代码
// 类组件:依赖可变的 this,状态修改隐含副作用
class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>; // this.props 是可变的(父组件更新时变化)
  }
}

相比之下,函数组件的优势很明显:

  • 可预测性:纯函数组件 "输入定,输出定",无需担心内部隐藏状态导致的 UI 错乱,调试时只需关注 props 和 state;
  • 简洁性:摆脱 this 绑定、生命周期钩子(如 componentDidMount)的复杂逻辑,代码更短、可读性更高;
  • 复用性:纯函数组件更容易通过组合(而非继承)复用(如自定义 Hooks)。

"不可变数据" 管理状态(避免隐性副作用)

函数式编程强调 "不可变数据"(数据创建后不修改,而是返回新副本),React 把这个思想贯穿到 状态更新(setState/useState) 和 Props 传递 中。

React 的状态(state)本质是 "不可变的":你不能直接修改状态对象 / 数组,必须返回一个新的副本,React 才会感知到状态变化并重新渲染。

jsx 复制代码
function TodoList() {
  // 初始化状态:todo 列表(数组)
  const [todos, setTodos] = React.useState([{ id: 1, text: '学习 FP' }]);

  // 添加新 todo:返回新数组(不修改原数组)
  const addTodo = (text) => {
    const newTodo = { id: Date.now(), text };
    // 正确:用扩展运算符创建新数组(不可变)
    setTodos([...todos, newTodo]);
    // 错误:直接修改原数组(React 无法感知变化)
    // todos.push(newTodo);
  };

  return (
    <div>
      {todos.map((todo) => (
        <p key={todo.id}>{todo.text}</p>
      ))}
      <button onClick={() => addTodo('学习 React FP')}>添加</button>
    </div>
  );
}

这种设计的优势:

  • 避免隐性副作用:直接修改原状态会导致 "状态变化不可追踪"(比如不知道什么时候、谁修改了状态),纯函数组件的 "输入 → 输出" 逻辑被打破;
  • React 渲染优化:React 通过 "浅比较" 判断状态 / Props 是否变化(比如比较数组引用是否改变),如果直接修改原数据,引用不变,React 会误以为状态没变化,不重新渲染;
  • 符合 FP 思想:不可变数据让状态变化 "可预测、可回溯",比如 Redux(React 生态的状态管理库)的核心就是 "不可变状态树"。

"副作用隔离"(用 Hooks 分离纯逻辑与副作用)

函数式编程强调 "纯函数无副作用",但前端开发无法避免副作用(如网络请求、DOM 操作、定时器)。React 没有禁止副作用,而是通过 Hooks(如 useEffect、useCallback) 将副作用与纯渲染逻辑 "隔离",让组件主体保持纯函数特性(组件主题(函数执行部分)只负责 "根据状态渲染 UI"(纯逻辑),副作用(如网络请求、DOM 操作、定时器)由专门的 Hooks 处理)。

jsx 复制代码
function UserProfile({ userId }) {
  const [user, setUser] = React.useState(null);

  // 副作用:发起网络请求(隔离在 useEffect 中)
  React.useEffect(() => {
    // 网络请求是副作用(依赖外部环境,有不确定性)
    fetch(`/api/user/${userId}`)
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, [userId]); // 依赖项:只有 userId 变化时,才重新执行副作用

  // 组件主体:纯逻辑(根据 user 状态渲染 UI)
  if (!user) return <div>加载中...</div>;
  return <div>姓名:{user.name}</div>;
}

这样设计的优势:

  • 组件职责单一:组件主体只关心 "渲染 UI",副作用交给专门的 Hooks 处理,符合 "单一职责原则";
  • 副作用可控制:useEffect 通过 "依赖项数组" 控制副作用的执行时机(如组件挂载时、依赖变化时),避免 "副作用泛滥";
  • 符合 FP 思想:纯函数负责 "计算"(渲染 UI),副作用负责 "与外部交互",两者分离,代码更易维护。

"函数组合" 实现组件复用(替代继承)

函数式编程强调 "用函数组合替代继承",React 把这个思想落地为 组件组合(Composition) 和 自定义 Hooks,替代了类组件的继承(如 extends React.Component)。

组件组合(Composition)通过 "组件嵌套" 和 "Props 传递" 实现复用,而非继承:

jsx 复制代码
// 通用组件:Button(纯函数组件)
function Button({ children, onClick }) {
  return (
    <button style={{ color: 'red' }} onClick={onClick}>
      {children}
    </button>
  );
}

// 业务组件:LoginButton(组合 Button 实现复用)
function LoginButton() {
  const handleLogin = () => console.log('登录');
  // 组合 Button,传递 Props,无需继承
  return <Button onClick={handleLogin}>登录</Button>;
}

// 业务组件:LogoutButton(组合 Button 实现复用)
function LogoutButton() {
  const handleLogout = () => console.log('退出');
  return <Button onClick={handleLogout}>退出</Button>;
}

把可复用的逻辑(纯逻辑 + 副作用)封装成自定义 Hooks,通过 "函数调用" 复用,而非组件继承:

jsx 复制代码
// 自定义 Hooks:封装"获取用户数据"的复用逻辑(纯逻辑 + 副作用)
function useUser(userId) {
  const [user, setUser] = React.useState(null);
  React.useEffect(() => {
    fetch(`/api/user/${userId}`)
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, [userId]);
  return user; // 返回结果,供组件使用
}

// 组件 A:复用 useUser 逻辑
function UserProfileA({ userId }) {
  const user = useUser(userId); // 函数调用,复用逻辑
  if (!user) return <div>加载中...</div>;
  return <div>姓名:{user.name}</div>;
}

// 组件 B:复用 useUser 逻辑
function UserCard({ userId }) {
  const user = useUser(userId); // 函数调用,复用逻辑
  if (!user) return <div>加载中...</div>;
  return <div>卡片:{user.name}</div>;
}

这样的设计优势:

  • 灵活性更高:继承会导致 "组件耦合"(子类依赖父类的实现),而组合和自定义 Hooks 是 "松耦合"(组件 / 逻辑通过参数传递,不依赖内部实现);
  • 符合 FP 思想:自定义 Hooks 本质是 "函数组合",把复杂逻辑拆解成小的、可复用的函数,与函数式编程 "用纯函数组合描述计算" 的思想一致。

总结:React 吸收 FP 思想的核心价值 React 采用函数式编程思想,不是为了 "赶潮流",而是为了解决前端开发的实际问题:

  • 可预测性:纯函数组件 + 不可变数据,让 UI 渲染 "输入定,输出定",减少状态混乱;
  • 可维护性:副作用隔离 + 函数组合,让代码职责清晰、易于复用和调试;
  • 性能优化:不可变数据 + 浅比较,让 React 渲染优化更高效;
  • 简洁性:摆脱类组件的 this 和生命周期,代码更短、学习成本更低。

面向对象编程(Object-Oriented Programming) - 对象

特点:一种以 "对象" 为核心的编程范式,核心思想是将现实世界中的实体抽象为 "对象"------ 每个对象包含 "描述实体的属性(数据)" 和 "实体能执行的行为(方法)",通过对象间的交互(调用方法、传递数据)完成复杂功能。

简单说,OOP 就像 "搭积木":把复杂系统拆分成一个个独立的 "积木块(对象)",每个积木块有自己的 "样子(属性)" 和 "功能(方法)",再通过积木块的组合拼接,搭建出完整的系统。

仍然是求和的例子,用面向对象编程的方式实现:

javascript 复制代码
// 类方式
class NumberProcessor {
  constructor(numbers) {
    this.numbers = numbers;
  }

  filterEven() {
    this.numbers = this.numbers.filter((n) => n % 2 === 0);
    return this;
  }

  square() {
    this.numbers = this.numbers.map((n) => n * n);
    return this;
  }

  sum() {
    return this.numbers.reduce((sum, n) => sum + n, 0);
  }

  sumOfEvenSquares() {
    return new NumberProcessor(this.numbers).filterEven().square().sum();
  }
}

// 使用
const processor = new NumberProcessor([1, 2, 3, 4, 5, 6]);
console.log(processor.sumOfEvenSquares()); // 56

// 或者使用对象字面量
const numberUtils = {
  isEven: (n) => n % 2 === 0,
  square: (n) => n * n,
  sum: (a, b) => a + b,

  sumOfEvenSquares(numbers) {
    return numbers.filter(this.isEven).map(this.square).reduce(this.sum, 0);
  },
};

console.log(numberUtils.sumOfEvenSquares([1, 2, 3, 4, 5, 6])); // 56

当然一般计算,不会想到用面向对象编程的方式实现,但这里就反应了面向对象编程的核心思想:把一切东西都抽象为对象。

OOP的四大核心特性

  • 封装(Encapsulation):将数据(属性)和行为(方法)封装在一起,形成一个独立的 "对象",对外隐藏内部实现细节,只暴露必要的接口(方法);
  • 继承(Inheritance):通过 "类" 和 "对象" 的继承关系,实现代码复用和扩展;
  • 多态(Polymorphism):通过 "方法重载" 和 "接口抽象",实现 "同名不同实现" 的灵活性;
  • 抽象(Abstraction):通过 "接口" 和 "抽象类",实现 "高内聚、低耦合" 的模块化设计。
js 复制代码
// 父类:Animal
// 将getName方法封装在父类中,对外隐藏内部实现细节,只暴露必要的接口(方法),这就是封装的体现
class Animal {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }

  // 父类方法(统一接口)
  makeSound() {
    console.log('动物发出声音');
  }
}

// 子类:Dog 继承了父类的getName方法,这就是继承的体现
class Dog extends Animal {
  // 重写父类的makeSound方法,这就是多态的体现
  makeSound() {
    console.log(`${this.name}:汪汪汪!`);
  }
}

// 子类:Cat(重写 makeSound) 这就是多态的体现
class Cat extends Animal {
  makeSound() {
    console.log(`${this.name}:喵喵喵!`);
  }
}

// 统一调用逻辑(不关心具体是哪个子类)
function animalSound(animal) {
  // 这就是多态的体现,不同对象调用同一方法,结果不同
  animal.makeSound(); // 同一方法调用,不同行为
}

// 多态体现:不同对象调用同一方法,结果不同
const dog = new Dog('旺财');
const cat = new Cat('咪宝');
animalSound(dog); // 旺财:汪汪汪!
animalSound(cat); // 咪宝:喵喵喵!

// 抽象就是你思考到核心的属性和方法,什么适合封装成一个父类,什么适合封装成一个子类,这就是抽象的体现

OOP的适用场景和优劣势

  • 适用场景:模拟现实世界的复杂实体(如 "用户、订单、商品" 等业务对象);大型复杂系统(如管理系统、游戏、框架),需要清晰的模块划分和复用
  • 优势:可读性高(代码结构贴近现实世界),易于维护和拓展(内部实现细节对外隐藏,继承和多态让代码更灵活),模块化清晰(高内聚、低耦合)
  • 劣势:可能过度设计(如果一个系统很小,却要使用OOP,可能会过度设计),性能开销(继承和多态会有一定的性能开销),继承可能导致紧耦合(如果一个系统很大,却要使用OOP,可能会导致代码过于复杂,难以维护)

范式对比总结

范式 关注点 适用场景 代码风格
命令式 如何做 性能敏感、底层操作 循环、条件语句
声明式 做什么 数据处理、UI 构建 链式调用、表达式
函数式 函数组合 数据处理、数学计算 纯函数、不可变数据
面向对象 对象和类 大型系统、GUI 应用 类、继承、封装

实际应用建议

实际项目中通常混合使用多种范式,不同场景适合不同范式。

来一个综合使用的例子: 假设需实现一个 "电商订单处理流程",包含以下功能:

  1. 定义订单实体(含商品、金额、状态等)。
  2. 筛选符合条件的订单(如 "已付款且金额> 100 元")。
  3. 计算订单总金额(含折扣:满 200 减 20)。
  4. 输出处理结果。
javascript 复制代码
// 1. 面向对象编程(OOP):定义订单实体(封装属性和行为)
class Order {
  constructor(id, products, isPaid) {
    this.id = id;
    this.products = products; // 商品列表({name: string, price: number})
    this.isPaid = isPaid; // 是否付款
  }

  // 计算订单原始总金额(封装行为)
  getTotalPrice() {
    return this.products.reduce((sum, p) => sum + p.price, 0);
  }
}

// 2. 函数式编程(FP):纯函数处理数据(不可变、无副作用)
// 纯函数:计算折扣后金额
const calculateDiscount = (total) => (total >= 200 ? total - 20 : total);

// 纯函数:筛选符合条件的订单(已付款且原始金额>100)
const filterValidOrders = (orders) =>
  orders.filter((order) => order.isPaid && order.getTotalPrice() > 100);

// 3. 声明式编程:描述目标(筛选→计算折扣→汇总),隐藏步骤
const processOrders = (orders) =>
  filterValidOrders(orders)
    .map((order) => ({
      id: order.id,
      originalPrice: order.getTotalPrice(),
      discountedPrice: calculateDiscount(order.getTotalPrice()),
    }))
    .reduce(
      (summary, item) => {
        summary.totalOriginal += item.originalPrice;
        summary.totalDiscounted += item.discountedPrice;
        summary.details.push(item);
        return summary;
      },
      { totalOriginal: 0, totalDiscounted: 0, details: [] },
    );

// 4. 命令式编程:执行流程并输出结果(显式步骤)
function main() {
  // 初始化订单(命令式步骤:创建对象)
  const orders = [
    new Order(1, [{ name: '书', price: 50 }], true), // 金额50(不满足>100)
    new Order(2, [{ name: '手机', price: 250 }], true), // 金额250(满足)
    new Order(3, [{ name: '耳机', price: 150 }], false), // 未付款(不满足)
    new Order(
      4,
      [
        { name: '键盘', price: 120 },
        { name: '鼠标', price: 90 },
      ],
      true,
    ), // 金额210(满足)
  ];

  // 处理订单(调用声明式/函数式逻辑)
  const result = processOrders(orders);

  // 命令式输出(显式步骤:循环打印)
  console.log('有效订单处理结果:');
  for (let i = 0; i < result.details.length; i++) {
    // 命令式循环
    const item = result.details[i];
    console.log(`订单${item.id}:原价${item.originalPrice}元,折扣后${item.discountedPrice}元`);
  }
  console.log(`总计:原价${result.totalOriginal}元,折扣后${result.totalDiscounted}元`);
}

// 执行主函数
main();

main 函数的核心是 "流程控制",通过明确的步骤、显式的循环和指令,一步步引导计算机完成 "从初始化到输出" 的全流程,完全符合命令式编程 "关注如何做、步骤化执行" 的本质。

虽然内部调用了 processOrders(声明式 + 函数式),但这并不影响 main 本身是命令式 ------ 相当于 "命令式的流程" 中,调用了一个 "声明式的工具" 来完成某个子任务。

相关推荐
将编程培养成爱好4 小时前
C++ 设计模式《账本事故:当备份被删光那天》
开发语言·c++·设计模式·备忘录模式
FogLetter6 小时前
设计模式奇幻漂流:从单例孤岛到工厂流水线
前端·设计模式
guangzan10 小时前
常用设计模式:代理模式
设计模式
西幻凌云11 小时前
认识设计模式——单例模式
c++·单例模式·设计模式·线程安全·饿汉和懒汉
爱吃烤鸡翅的酸菜鱼12 小时前
【Java】基于策略模式 + 工厂模式多设计模式下:重构租房系统核心之城市房源列表缓存与高性能筛选
java·redis·后端·缓存·设计模式·重构·策略模式
在未来等你21 小时前
AI Agent设计模式 Day 5:Reflexion模式:自我反思与持续改进
设计模式·llm·react·ai agent·plan-and-execute
程序员三藏21 小时前
快速弄懂POM设计模式
自动化测试·软件测试·python·selenium·测试工具·设计模式·职场和发展
Lei_33596721 小时前
[設計模式]設計模式的作用
设计模式
将编程培养成爱好1 天前
C++ 设计模式《统计辅助功能》
开发语言·c++·设计模式·访问者模式