红宝书第十二讲:详解JavaScript中的工厂模式与原型模式等各种设计模式

红宝书第十二讲:详解JavaScript中的工厂模式与原型模式等各种设计模式

资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲


工厂模式和原型模式解析

一、工厂模式:像订外卖一样创建对象

工厂模式就像一个**"对象生成器"**,只需要告诉它"我要什么",它就会自动生成并返回对应的对象。适合需要批量创建复杂对象的场景 ^1^。

案例:点餐系统

假设你经营奶茶店,需要根据订单类型生成不同配置的饮品:

javascript 复制代码
// 工厂函数决定饮品类型和配料
function createDrink(type, name) {
  const drink = { name };
  if (type === '奶茶') {
    drink.base = '红茶';
    drink.toppings = ['珍珠', '奶盖'];
  } else if (type === '果茶') {
    drink.base = '四季春茶';
    drink.toppings = ['椰果', '寒天'];
  }
  return drink;
}

// 下单操作
const order1 = createDrink('奶茶', '招牌奶茶'); 
const order2 = createDrink('果茶', '满杯鲜橙');

^[1](#1: 参考资料6明确将工厂模式列为JavaScript对象创建的核心设计模式 "#user-content-fn-1")^: 参考资料6明确将工厂模式列为JavaScript对象创建的核心设计模式


二、原型模式:共享技能的忍者军团

原型模式的精髓是**"多人共用同一套技能"**。将公共方法存放在原型(prototype)中,所有实例无需重复存储这些方法 ^2^。

示例:游戏中的敌人构造
javascript 复制代码
// 定义敌人原型
function Enemy(type) {
  this.type = type;
}

// 共享攻击方法(所有敌人都会)
Enemy.prototype.attack = function() {
  console.log(`${this.type}发起攻击!`);
};

// 创建实例
const dragon = new Enemy('火龙');
const goblin = new Enemy('哥布林');

dragon.attack();  // 火龙发起攻击!
goblin.attack();  // 哥布林发起攻击!

// 验证方法共享
console.log(dragon.attack === goblin.attack); // true ✅

^[2](#2: 参考资料4通过Person.prototype案例证明原型共享方法的有效性 "#user-content-fn-2")^: 参考资料4通过Person.prototype案例证明原型共享方法的有效性

flowchart LR Enemy.prototype --> 共享方法attack dragon实例 -->|.__proto__| Enemy.prototype goblin实例 -->|.__proto__| Enemy.prototype

为什么用原型?

  1. 内存节省 :1000个实例共享1个方法,而非存储1000份 ^3^
  2. 动态更新:在原型添加新方法,现有实例即时生效

例如新增Enemy.prototype.run = function() { ... },所有敌人都能调用.run()


三、对比总结

模式 适用场景 优点 缺点
工厂模式 需要灵活创建多类型对象 隐藏创建细节,代码简洁 类型识别困难(如无法用instanceof
原型模式 大量对象需共享方法或属性 节省内存,动态扩展性强 复杂属性需独立初始化(如对象引用)

^[3](#3: 参考资料3强调代码维护性需通过共享结构实现,这正是原型模式的核心优势 "#user-content-fn-3")^: 参考资料3强调代码维护性需通过共享结构实现,这正是原型模式的核心优势

好的!以下是根据你的要求修改后的版本,增加了对比表格、详细说明文字以及代码注释。


JavaScript 常用设计模式解析

一、设计模式特点对比表

设计模式 主要用途 优点 缺点
工厂模式 创建多种类型的对象,隐藏创建逻辑,提供统一的创建接口 简化对象创建逻辑,易于扩展和维护 增加了系统的复杂性,可能需要维护多个工厂类
单例模式 确保一个类只有一个实例,并提供全局访问点 避免重复实例化,节省资源,便于管理全局状态 可能导致代码难以测试,过度使用会限制系统的灵活性
原型模式 通过复制现有对象创建新对象,避免复杂的初始化过程 性能优化,减少重复代码,易于创建多个类似对象 可能导致对象之间的关系复杂,难以管理
代理模式 提供一个代理对象来控制对实际对象的访问,添加额外逻辑 可以在不修改原始对象的情况下添加功能,如权限控制、缓存等 增加了系统的复杂性,可能影响性能
观察者模式 定义对象间的一对多依赖关系,当一个对象改变时,所有依赖它的对象都会得到通知 实现了对象间的松耦合,便于扩展和维护 可能导致通知风暴,影响性能,且依赖关系复杂
策略模式 定义一系列算法,封装起来并使它们可互换 提供了算法的可切换性,易于扩展和维护 可能导致策略类过多,增加系统的复杂性
装饰者模式 动态地给对象添加额外的功能,而不改变其结构 提供了比继承更灵活的扩展方式,易于添加新功能 可能导致装饰器过多,影响性能和可读性
适配器模式 将一个类的接口转换成客户希望的另一个接口 提高了类的兼容性,避免了修改现有代码 增加了系统的复杂性,可能隐藏了接口的不一致性
模板方法模式 定义一个操作中的算法框架,将某些步骤延迟到子类中 提供了代码复用性,便于维护和扩展 子类可能过度依赖父类,限制了灵活性
建造者模式 逐步构建一个复杂的对象,隐藏构建过程 提供了构建过程的灵活性,易于扩展和维护 可能增加系统的复杂性,需要维护多个建造者类

二、设计模式详细解析

1. 工厂模式(Factory Pattern)

详细说明

工厂模式就像一个"制造机器",它的主要任务是根据不同的需求创建不同类型的对象,而不需要直接使用 new 关键字去实例化对象。想象一下,你去玩具店买玩具,你只需要告诉店员你想要什么类型的玩具(比如小汽车、洋娃娃),店员就会给你制造出对应类型的玩具,而你不需要自己去组装玩具。工厂模式的核心在于隐藏了对象的创建细节,让使用者只需要关心对象的使用,而不需要关心对象是如何被创建的。

代码示例

javascript 复制代码
// 定义一个基类 Animal
class Animal {
  speak() {
    return this.makeSound();
  }
}

// 定义具体的 Dog 类
class Dog extends Animal {
  makeSound() {
    return "Woof"; // 狗的叫声
  }
}

// 定义具体的 Cat 类
class Cat extends Animal {
  makeSound() {
    return "Meow"; // 猫的叫声
  }
}

// 工厂类,负责创建不同类型的动物对象
class AnimalFactory {
  createAnimal(type) {
    switch (type) {
      case "dog":
        return new Dog(); // 创建 Dog 实例
      case "cat":
        return new Cat(); // 创建 Cat 实例
      default:
        throw new Error("Unknown animal type"); // 如果类型未知,抛出错误
    }
  }
}

// 使用工厂模式创建对象
const factory = new AnimalFactory();
const dog = factory.createAnimal("dog"); // 创建 Dog 实例
console.log(dog.speak()); // 输出:Woof
const cat = factory.createAnimal("cat"); // 创建 Cat 实例
console.log(cat.speak()); // 输出:Meow

代码注释

  • Animal 是一个基类,定义了一个通用的 speak 方法。
  • DogCat 是具体的动物类,分别实现了 makeSound 方法。
  • AnimalFactory 是工厂类,通过 createAnimal 方法根据传入的类型参数创建对应的动物对象。
  • 使用工厂模式时,我们只需要通过工厂类的 createAnimal 方法来获取对象,而不需要直接使用 new 关键字。

流程图

graph TD A[开始] --> B[创建工厂实例] B --> C[调用工厂方法] C --> D{根据类型判断} D -- dog --> E[创建Dog实例] D -- cat --> F[创建Cat实例] E --> G[返回Dog实例] F --> H[返回Cat实例] G --> I[使用实例] H --> I I --> J[结束]

2. 单例模式(Singleton Pattern)

详细说明

单例模式确保一个类只有一个实例,并提供一个全局访问点。想象一下,一个国家的总统,全国只能有一个总统,不管你从哪里获取总统的信息,都是同一个总统对象。如果已经有一个总统实例了,再获取总统对象时,就直接返回这个已经存在的实例,而不是再创建一个新的。单例模式的核心在于保证全局唯一性,避免重复实例化,节省资源。

代码示例

javascript 复制代码
// 定义一个 Logger 类
class Logger {
  constructor() {
    if (Logger.instance) {
      return Logger.instance; // 如果已经存在实例,直接返回
    }
    this.messages = []; // 用于存储日志消息
    Logger.instance = this; // 保存当前实例
  }

  log(message) {
    this.messages.push(message); // 添加日志消息
  }

  getLogs() {
    return this.messages; // 获取所有日志消息
  }
}

// 使用单例模式
const logger1 = new Logger();
logger1.log("Hello"); // 添加日志

const logger2 = new Logger();
logger2.log("World"); // 添加日志

console.log(logger1.getLogs()); // 输出:["Hello", "World"]
console.log(logger1 === logger2); // 输出:true(logger1 和 logger2 是同一个实例)

代码注释

  • Logger 类中有一个静态属性 instance,用于保存唯一的实例。
  • 在构造函数中,如果 Logger.instance 已经存在,则直接返回已存在的实例,否则创建一个新的实例并保存到 Logger.instance 中。
  • 通过 log 方法添加日志消息,通过 getLogs 方法获取所有日志消息。
  • 无论创建多少次 Logger 实例,始终返回同一个实例,确保全局唯一性。

流程图

graph TD A[开始] --> B[创建Logger实例] B --> C{是否已存在实例} C -- 是 --> D[返回已存在的实例] C -- 否 --> E[创建新实例] E --> F[保存实例] F --> G[使用实例] D --> G G --> H[结束]

3. 原型模式(Prototype Pattern)

详细说明

原型模式允许通过复制现有的对象来创建新的对象,而不需要通过构造函数来创建。想象一下,你有一个已经配置好的电脑模板,你可以直接复制这个模板来创建新的电脑,而不需要重新配置。原型模式的核心在于通过对象的复制来创建新对象,避免了复杂的初始化过程,提高了性能。

代码示例

javascript 复制代码
// 定义一个原型对象
const animalPrototype = {
  speak() {
    return this.makeSound(); // 调用 makeSound 方法
  },
};

// 通过 Object.create 复制原型对象创建 Dog 实例
const dog = Object.create(animalPrototype);
dog.makeSound = function () {
  return "Woof"; // 狗的叫声
};

// 通过 Object.create 复制原型对象创建 Cat 实例
const cat = Object.create(animalPrototype);
cat.makeSound = function () {
  return "Meow"; // 猫的叫声
};

console.log(dog.speak()); // 输出:Woof
console.log(cat.speak()); // 输出:Meow

代码注释

  • animalPrototype 是一个原型对象,定义了一个通用的 speak 方法。
  • 使用 Object.create 方法,通过复制 animalPrototype 来创建 dogcat 实例。
  • 每个实例都可以通过覆盖 makeSound 方法来定义自己的行为。
  • 这种方式避免了通过构造函数创建对象的复杂性,同时保持了对象的继承关系。

流程图

graph TD A[开始] --> B[创建原型对象] B --> C[复制原型对象] C --> D[修改复制对象的属性] D --> E[使用复制对象] E --> F[结束]

4. 代理模式(Proxy Pattern)

详细说明

代理模式通过创建一个代理对象来控制对实际对象的访问,代理对象可以添加额外的逻辑,比如权限检查、缓存、远程调用等。想象一下,你去银行取钱,银行柜员就是一个代理,他可以检查你的身份,确认你有权限取钱后,才会让你取钱。代理模式的核心在于在不修改原始对象的情况下,添加额外的控制逻辑。

代码示例

javascript 复制代码
// 定义一个真实对象
class RealSubject {
  request() {
    return "RealSubject: Handling request."; // 真实对象的请求方法
  }
}

// 定义一个代理对象
class Proxy {
  constructor(realSubject) {
    this.realSubject = realSubject; // 保存真实对象的引用
  }

  request() {
    if (this.checkAccess()) { // 检查权限
      this.realSubject.request(); // 调用真实对象的请求方法
      this.logAccess(); // 记录日志
    }
  }

  checkAccess() {
    console.log("Proxy: Logging the time of request."); // 记录请求时间
    return true; // 假设权限检查通过
  }

  logAccess() {
    console.log("Proxy: Logging the request."); // 记录请求
  }
}

// 使用代理模式
const realSubject = new RealSubject(); // 创建真实对象
const proxy = new Proxy(realSubject); // 创建代理对象
proxy.request(); // 调用代理的请求方法

代码注释

  • RealSubject 是真实对象,定义了一个 request 方法。
  • Proxy 是代理对象,通过 request 方法控制对真实对象的访问。
  • 在调用真实对象的 request 方法之前,代理对象会执行额外的逻辑,如权限检查和日志记录。
  • 通过代理模式,可以在不修改真实对象的情况下,添加额外的功能。

流程图

graph TD A[开始] --> B[创建真实对象] B --> C[创建代理对象] C --> D[调用代理的请求方法] D --> E[检查权限] E -- 有权限 --> F[调用真实对象的方法] F --> G[记录日志] G --> H[结束] E -- 无权限 --> H

5. 观察者模式(Observer Pattern)

详细说明

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,所有依赖它的观察者都会自动收到通知并进行更新。想象一下,你关注了一个博主,当博主发布新的文章时,你会收到通知。观察者模式的核心在于实现对象间的松耦合,当一个对象改变时,其他对象可以自动响应。

代码示例

javascript 复制代码
// 定义一个主题对象
class Subject {
  constructor() {
    this.observers = []; // 保存观察者列表
  }

  addObserver(observer) {
    this.observers.push(observer); // 添加观察者
  }

  removeObserver(observer) {
    this.observers = this.observers.filter((obs) => obs !== observer); // 移除观察者
  }

  notify() {
    this.observers.forEach((observer) => observer.update()); // 通知所有观察者
  }
}

// 定义一个观察者对象
class Observer {
  update() {
    console.log("Observer: I've been notified!"); // 观察者收到通知后的响应
  }
}

// 使用观察者模式
const subject = new Subject(); // 创建主题对象
const observer1 = new Observer(); // 创建观察者1
const observer2 = new Observer(); // 创建观察者2

subject.addObserver(observer1); // 添加观察者1
subject.addObserver(observer2); // 添加观察者2

subject.notify(); // 通知所有观察者

代码注释

  • Subject 是主题对象,维护一个观察者列表,并提供添加、移除和通知观察者的方法。
  • Observer 是观察者对象,定义了一个 update 方法,用于响应通知。
  • 当主题对象的状态发生变化时,通过调用 notify 方法通知所有观察者。
  • 观察者模式实现了对象间的松耦合,便于扩展和维护。

流程图

graph TD A[开始] --> B[创建主题对象] B --> C[创建观察者对象] C --> D[将观察者添加到主题] D --> E[主题状态改变] E --> F[通知所有观察者] F --> G[观察者执行更新] G --> H[结束]

6. 策略模式(Strategy Pattern)

详细说明

策略模式定义了一系列的算法,把它们封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户。想象一下,你有一个计算器,可以选择不同的运算方式(如加法、减法)。策略模式的核心在于通过封装不同的算法,让客户端可以在运行时动态选择算法,而不需要修改代码。

代码示例

javascript 复制代码
// 定义一个上下文对象
class Context {
  constructor(strategy) {
    this.strategy = strategy; // 保存策略对象
  }

  executeStrategy(a, b) {
    return this.strategy(a, b); // 执行策略
  }
}

// 定义加法策略
function addStrategy(a, b) {
  return a + b; // 加法运算
}

// 定义减法策略
function subtractStrategy(a, b) {
  return a - b; // 减法运算
}

// 使用策略模式
const context = new Context(addStrategy); // 使用加法策略
console.log(context.executeStrategy(10, 5)); // 输出:15

context.strategy = subtractStrategy; // 切换到减法策略
console.log(context.executeStrategy(10, 5)); // 输出:5

代码注释

  • Context 是上下文对象,保存一个策略对象,并通过 executeStrategy 方法执行策略。
  • addStrategysubtractStrategy 是具体的策略,分别实现加法和减法运算。
  • 客户端可以通过动态更换策略对象来改变行为,而不需要修改上下文对象的代码。

流程图

graph TD A[开始] --> B[创建上下文对象] B --> C[设置策略] C --> D[执行策略] D --> E[输出结果] E --> F[结束]

7. 装饰者模式(Decorator Pattern)

详细说明

装饰者模式允许动态地给一个对象添加额外的功能,而不需要修改其结构。想象一下,你有一件衣服,你可以通过添加装饰(如徽章、刺绣)来改变它的外观,而不需要改变衣服本身的结构。装饰者模式的核心在于通过组合的方式,动态地扩展对象的功能。

代码示例

javascript 复制代码
// 定义一个组件基类
class Component {
  operation() {
    return "Component"; // 基类的通用方法
  }
}

// 定义具体的组件类
class ConcreteComponent extends Component {
  operation() {
    return "ConcreteComponent"; // 具体组件的实现
  }
}

// 定义装饰者类
class Decorator extends Component {
  constructor(component) {
    super();
    this.component = component; // 保存组件对象
  }

  operation() {
    return `Decorator(${this.component.operation()})`; // 调用组件对象的方法,并添加额外逻辑
  }
}

// 使用装饰者模式
const component = new ConcreteComponent(); // 创建具体组件
console.log(component.operation()); // 输出:ConcreteComponent

const decoratedComponent = new Decorator(component); // 创建装饰者
console.log(decoratedComponent.operation()); // 输出:Decorator(ConcreteComponent)

代码注释

  • Component 是组件基类,定义了一个通用的 operation 方法。
  • ConcreteComponent 是具体的组件类,实现了 operation 方法。
  • Decorator 是装饰者类,通过组合的方式保存一个组件对象,并在调用组件对象的方法时添加额外的逻辑。
  • 通过装饰者模式,可以在不修改组件类的情况下,动态地扩展功能。

流程图

graph TD A[开始] --> B[创建组件对象] B --> C[创建装饰者对象] C --> D[装饰者调用组件方法] D --> E[输出结果] E --> F[结束]

8. 适配器模式(Adapter Pattern)

详细说明

适配器模式将一个类的接口转换成客户希望的另一个接口,使原本不兼容的接口能够兼容。想象一下,你有一个充电器,但它只能给手机充电,而你有一个平板电脑需要充电。适配器模式的核心在于通过一个适配器对象,将充电器的接口转换为平板电脑可以使用的接口,从而实现兼容。

代码示例

javascript 复制代码
// 定义一个媒体播放器接口
class MediaPlayer {
  play(audioType, fileName) {
    console.log(`Playing ${audioType} file. Name: ${fileName}`); // 播放音频文件
  }
}

// 定义一个高级媒体播放器接口
class AdvancedMediaPlayer {
  playVlc(fileName) {
    console.log(`Playing VLC file. Name: ${fileName}`); // 播放 VLC 文件
  }

  playMp4(fileName) {
    console.log(`Playing MP4 file. Name: ${fileName}`); // 播放 MP4 文件
  }
}

// 定义一个适配器类
class MediaAdapter extends MediaPlayer {
  constructor(audioType, advancedMediaPlayer) {
    super();
    this.audioType = audioType; // 保存音频类型
    this.advancedMediaPlayer = advancedMediaPlayer; // 保存高级媒体播放器对象
  }

  play(audioType, fileName) {
    if (audioType === "vlc") {
      this.advancedMediaPlayer.playVlc(fileName); // 调用高级媒体播放器的 playVlc 方法
    } else if (audioType === "mp4") {
      this.advancedMediaPlayer.playMp4(fileName); // 调用高级媒体播放器的 playMp4 方法
    }
  }
}

// 使用适配器模式
const mediaPlayer = new MediaPlayer(); // 创建媒体播放器对象
const advancedMediaPlayer = new AdvancedMediaPlayer(); // 创建高级媒体播放器对象
const mediaAdapter = new MediaAdapter("vlc", advancedMediaPlayer); // 创建适配器对象

mediaAdapter.play("vlc", "song.vlc"); // 通过适配器播放 VLC 文件

代码注释

  • MediaPlayer 是媒体播放器接口,定义了一个 play 方法。
  • AdvancedMediaPlayer 是高级媒体播放器接口,定义了 playVlcplayMp4 方法。
  • MediaAdapter 是适配器类,通过继承 MediaPlayer 并保存一个 AdvancedMediaPlayer 对象,将高级媒体播放器的接口适配到媒体播放器的接口。
  • 通过适配器模式,可以让客户端代码(MediaPlayer)调用高级媒体播放器的方法,实现接口的兼容。

流程图

graph TD A[开始] --> B[创建MediaPlayer实例] B --> C[创建AdvancedMediaPlayer实例] C --> D[创建适配器实例] D --> E[调用适配器的play方法] E --> F{判断音频类型} F -- vlc --> G[调用playVlc方法] F -- mp4 --> H[调用playMp4方法] G --> I[输出结果] H --> I I --> J[结束]

9. 模板方法模式(Template Method Pattern)

详细说明

模板方法模式定义了一个操作中的算法的框架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法的结构即可重定义算法的某些特定步骤。想象一下,你有一个烤面包机,它有一个固定的烤面包流程(预热、烤面包、冷却),但你可以通过更换不同的面包片来改变烤面包的结果。模板方法模式的核心在于通过定义一个算法框架,让子类可以在不改变框架的情况下,实现具体的步骤。

代码示例

javascript 复制代码
// 定义一个抽象类
class AbstractClass {
  templateMethod() {
    this.baseOperation1(); // 执行基础操作1
    this.requiredOperations1(); // 执行需要子类实现的操作1
    this.baseOperation2(); // 执行基础操作2
    this.hook1(); // 执行钩子方法1
    this.requiredOperations2(); // 执行需要子类实现的操作2
    this.baseOperation3(); // 执行基础操作3
    this.hook2(); // 执行钩子方法2
  }

  baseOperation1() {
    console.log("AbstractClass says: I am doing the bulk of the work"); // 基础操作1
  }

  baseOperation2() {
    console.log("AbstractClass says: But I let subclasses alter some specific steps"); // 基础操作2
  }

  baseOperation3() {
    console.log("AbstractClass says: But I am doing the bulk of the work anyway"); // 基础操作3
  }

  hook1() {} // 钩子方法1
  hook2() {} // 钩子方法2
}

// 定义一个具体的子类
class ConcreteClass1 extends AbstractClass {
  requiredOperations1() {
    console.log("ConcreteClass1 says: Implemented Operation1"); // 子类实现的操作1
  }

  requiredOperations2() {
    console.log("ConcreteClass1 says: Implemented Operation2"); // 子类实现的操作2
  }
}

// 定义另一个具体的子类
class ConcreteClass2 extends AbstractClass {
  requiredOperations1() {
    console.log("ConcreteClass2 says: Implemented Operation1"); // 子类实现的操作1
  }

  requiredOperations2() {
    console.log("ConcreteClass2 says: Implemented Operation2"); // 子类实现的操作2
  }

  hook1() {
    console.log("ConcreteClass2 says: Overridden Hook1"); // 子类重写的钩子方法1
  }
}

// 使用模板方法模式
const template1 = new ConcreteClass1(); // 创建具体子类1
template1.templateMethod(); // 调用模板方法

const template2 = new ConcreteClass2(); // 创建具体子类2
template2.templateMethod(); // 调用模板方法

代码注释

  • AbstractClass 是抽象类,定义了一个模板方法 templateMethod,它按顺序调用一系列操作,包括基础操作和需要子类实现的操作。
  • ConcreteClass1ConcreteClass2 是具体的子类,分别实现了 requiredOperations1requiredOperations2 方法。
  • 子类可以通过重写钩子方法(如 hook1hook2)来扩展模板方法的行为。
  • 模板方法模式允许子类在不改变算法结构的情况下,实现具体的步骤。

流程图

graph TD A[开始] --> B[创建抽象类] B --> C[定义模板方法] C --> D[调用基础操作] D --> E[调用子类实现的操作] E --> F[调用钩子方法] F --> G[结束]

10. 建造者模式(Builder Pattern)

详细说明

建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。想象一下,你正在建造一座房子,你需要逐步完成不同的步骤(如打地基、建墙壁、安装门窗)。建造者模式的核心在于通过一个建造者对象逐步构建复杂对象,隐藏具体的构建过程,让客户端只需要关心最终的结果。

代码示例

javascript 复制代码
// 定义一个复杂对象
class Car {
  constructor() {
    this.type = null; // 车型
    this.seats = null; // 座位数
    this.engine = null; // 发动机类型
    this.tripComputer = null; // 是否有行程计算机
    this.gps = null; // 是否有 GPS
  }
}

// 定义一个建造者类
class CarBuilder {
  constructor() {
    this.car = new Car(); // 创建一个 Car 实例
  }

  setType(type) {
    this.car.type = type; // 设置车型
    return this; // 返回当前对象,支持链式调用
  }

  setSeats(seats) {
    this.car.seats = seats; // 设置座位数
    return this; // 返回当前对象,支持链式调用
  }

  setEngine(engine) {
    this.car.engine = engine; // 设置发动机类型
    return this; // 返回当前对象,支持链式调用
  }

  setTripComputer(tripComputer) {
    this.car.tripComputer = tripComputer; // 设置行程计算机
    return this; // 返回当前对象,支持链式调用
  }

  setGPS(gps) {
    this.car.gps = gps; // 设置 GPS
    return this; // 返回当前对象,支持链式调用
  }

  build() {
    return this.car; // 返回构建好的 Car 实例
  }
}

// 使用建造者模式
const carBuilder = new CarBuilder(); // 创建建造者对象
const car = carBuilder
  .setType("SUV") // 设置车型为 SUV
  .setSeats(4) // 设置座位数为 4
  .setEngine("V6") // 设置发动机类型为 V6
  .setTripComputer(true) // 设置行程计算机为 true
  .setGPS(true) // 设置 GPS 为 true
  .build(); // 构建汽车

console.log(car); // 输出构建好的汽车对象

代码注释

  • Car 是一个复杂对象,包含多个属性(如车型、座位数、发动机类型等)。
  • CarBuilder 是建造者类,通过一系列的设置方法(如 setTypesetSeats 等)逐步构建 Car 对象。
  • 每个设置方法都返回当前建造者对象,支持链式调用,最后通过 build 方法返回构建好的 Car 对象。
  • 建造者模式隐藏了构建过程的细节,让客户端只需要关心最终的结果。

流程图

graph TD A[开始] --> B[创建建造者实例] B --> C[设置类型] C --> D[设置座位数] D --> E[设置发动机] E --> F[设置行程计算机] F --> G[设置GPS] G --> H[构建汽车] H --> I[结束]

希望这些详细的说明和代码注释能帮助你更好地理解这些设计模式!


目录:总目录 上篇文章:红宝书第十一讲:超易懂版「ES6类与继承」零基础教程:用现实例子+图解实现

脚注

Footnotes

  1. 《JavaScript高级程序设计(第5版)》索引的"factory pattern"验证工厂模式的代码组织形式。 2

  2. 《JavaScript高级程序设计(第5版)》通过Person类与.prototype的关联说明原型共享机制。 2

  3. 《JavaScript高级程序设计(第5版)》指出代码可维护性的核心在于避免冗余,与原型设计理念一致。 2

相关推荐
一丝晨光33 分钟前
数值溢出保护?数值溢出应该是多少?Swift如何让整数计算溢出不抛出异常?类型最大值和最小值?
java·javascript·c++·rust·go·c·swift
小堃学编程44 分钟前
前端学习(3)—— CSS实现热搜榜
前端·学习
Wannaer1 小时前
从 Vue3 回望 Vue2:响应式的内核革命
前端·javascript·vue.js
不灭锦鲤1 小时前
xss-labs靶场基础8-10关(记录学习)
前端·学习·xss
Bl_a_ck1 小时前
--openssl-legacy-provider is not allowed in NODE_OPTIONS 报错的处理方式
开发语言·前端·web安全·网络安全·前端框架·ssl
懒羊羊我小弟1 小时前
手写符合Promise/A+规范的Promise类
前端·javascript
互联网搬砖老肖1 小时前
Web 架构之负载均衡会话保持
前端·架构·负载均衡
赵大仁1 小时前
React vs Vue:点击外部事件处理的对比与实现
javascript·vue.js·react.js
肥肥呀呀呀3 小时前
在Flutter上如何实现按钮的拖拽效果
前端·javascript·flutter
Zero1017133 小时前
【React的useMemo钩子详解】
前端·react.js·前端框架