代理模式:从0-1了解JavaScript代理模式

40 阅读3分钟

JavaScript 语言特性

JavaScript 是一种弱类型、动态的、灵活的解释性脚本语言。

弱类型特性详解

与强类型语言不同,JavaScript 具有以下特点:

// 变量可以随时改变类型
let juejin = 21;          // 数字类型
juejin = "hello";          // 字符串类型  
juejin = { age: 21 };     // 对象类型

// 自动类型转换
console.log("5" + 3);  // "53" - 数字转字符串
console.log("5" - 3);  // 2 - 字符串转数字

数据类型分类

简单数据类型:

  • String: "juejin"
  • Number: 21
  • Boolean: true/false
  • undefined, null

复杂数据类型:

  • Object: { name: "juejin", age: 21 }
  • Array: [1, 2, 3]
  • Function: function() {}

面向对象思想

面向对象编程是现实世界和关系的软件抽象化,遵循基本规则:

对象的组成

  • 属性:用于描述对象特征
  • 方法:定义对象的行为和动作
// 对象示例
const person = {
  // 属性
  name: "juejin",
  age: 21,
  
  // 方法  
  introduce: function() {
    console.log(`我是${this.name},今年${this.age}岁`);
  }
};

JavaScript 运行环境

编译型 vs 解释型语言对比

编译型语言(如 C++): 源代码(.cpp) → 编译 → 目标文件(.o) → 链接 → 可执行文件
解释型语言(JavaScript): 源代码(.js) → 直接解释执行

前端运行方式

1,本地文件方式:

<!DOCTYPE html>
<html>
<head>
  <title>送花代理示例</title>
</head>
<body>
  <script src="flower.js"></script>
</body>
</html>

2. HTTP 协议远程访问: 通过 Web 服务器访问在线 JavaScript 文件

后端运行

# 使用 Node.js 在命令行运行
node flower.js

代理模式详解 - 送花场景

设计模式概念

面向对象系统的世界复杂,类似于现实世界。通过设计模式可以更好地组织代码结构。

代理模式实现

// 小美 - 目标对象
const 小美 = {
  name: "小美",
  mood: "good",
  
  receiveFlower: function(flower) {
    console.log(`${this.name}收到了${flower}`);
    return `${this.name}很开心`;
  },
  
  getMood: function() {
    return this.mood;
  }
};

// 小红 - 代理对象(老乡,闺蜜)
const 小红 = {
  name: "小红",
  target: 小美,  // 持有目标对象引用
  
  // 实现相同的接口
  receiveFlower: function(flower) {
    console.log(`${this.name}代收花束...`);
    
    // 代理逻辑 - 检查小美心情
    if (this.target.getMood() === "bad") {
      console.log("小美心情不好,改天再送吧");
      return "代理拒绝";
    }
    
    // 转发给目标对象
    const result = this.target.receiveFlower(flower);
    console.log(`${this.name}完成代理任务`);
    return result;
  }
};

// 小彭送花
function 小彭送花(receiver, flower) {
  console.log(`小彭准备送${flower}...`);
  return receiver.receiveFlower(flower);
}

// 使用代理模式
小彭送花(小红, "玫瑰花");

代理模式的核心优势

  1. 接口一致性

    • 小红和小美都实现了 receiveFlower 方法
    • 方法名相同,可以互换使用
    • 体现了面向接口编程思想
  2. 逻辑自由度

    • 代理送花的逻辑完全由开发者控制
    • 可以在调用前后添加额外处理
    • 不修改目标对象的情况下扩展功能
  3. 面向接口编程

    • 设计接口而非实现
    • 面向对象思想的高级表现
    • 典型的设计模式应用

代理模式扩展应用

// 缓存代理
const CacheProxy = {
  cache: new Map(),
  target: 小美,
  
  receiveFlower: function(flower) {
    const key = `${flower}_${Date.now()}`;
    
    if (this.cache.has(flower)) {
      console.log("从缓存获取结果");
      return this.cache.get(flower);
    }
    
    const result = this.target.receiveFlower(flower);
    this.cache.set(flower, result);
    return result;
  }
};

// 权限代理
const PermissionProxy = {
  target: 小美,
  allowedSenders: ["小彭", "小明"],
  
  receiveFlower: function(flower, sender) {
    if (!this.allowedSenders.includes(sender)) {
      console.log(`${sender}没有送花权限`);
      return "拒绝接收";
    }
    
    return this.target.receiveFlower(flower);
  }
};

总结

通过花朵代理模式的例子,我们深入理解了:

代理模式的优势:

  1. 职责分离:代理对象处理额外逻辑,目标对象专注核心功能
  2. 开闭原则:不修改原对象就能扩展功能
  3. 控制访问:可以在访问目标对象前后添加权限检查、日志记录等
  4. 性能优化:通过缓存、延迟加载等方式优化性能

代理模式体现了面向接口编程的思想,是 23 种设计模式中的结构型模式,在实际开发中应用广泛,也是常见面试中的经典。

总结

JavaScript 的弱类型特性为开发带来了灵活性,但也需要开发者更加小心处理类型相关问题。代理模式作为一种重要的设计模式,提供了在不修改原对象的情况下扩展功能的优雅解决方案,是面向对象编程中的重要概念。 代理模式让我们拥有了送花逻辑的自由控制权,是面向对象设计模式的典型应用,体现了软件工程中"开闭原则"的重要思想。