这里写目录标题
- 一、基本概念
- 二、单例模式
- 1. 模式特点
- 2. 适用场景
- 3. 实现方法
- 4. 经典示例
- 三、简单工厂模式
- 1. 模式特点
- 2. 经典示例
- 四、工厂方法模式
- 五、抽象工厂模式
- 1. 适用场景
- 2. 经典示例
- 六、建造者模式
- 1. 模式特点
- 2. 一般流程
- 3. 适用场景
- 4. 经典示例
- 七、原型模式
一、基本概念
创建型模式(Creational)是一种设计模式类别,用于解决与对象创建相关的常见问题。
单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
抽象类概念:
在面向对象编程中有以下几个主要作用:
-
提供一种约束和规范: 抽象类可以定义一些抽象方法,子类必须实现这些方法。这样可以约束子类在继承抽象类时必须按照一定的规范来实现这些方法,确保代码的一致性和可维护性。
-
封装通用的属性和方法: 抽象类可以包含一些通用的属性和方法,这样子类就可以继承这些属性和方法,避免了重复编写代码。通过继承抽象类,子类可以共享抽象类中已经实现的功能。
-
实现多态性: 抽象类可以作为多个具体子类的类型,通过抽象类可以实现多态性的特性。在编程中,可以通过抽象类来声明变量或参数的类型,然后在运行时根据实际的具体子类对象赋值给这些变量或参数实现不同子类对象的统一对待。
-
降低耦合度: 抽象类可以作为中间层,将具体实现和调用方进行解耦。调用方可以通过抽象类进行交互,而不必依赖具体的子类。这样可以提高代码的灵活性和可维护性,方便进行扩展和修改。
总结: 抽象类在面向对象编程中起到了规范、封装、多态和解耦的作用,使得代码更加灵活、可扩展和可维护。
二、单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。
1. 模式特点
-
节约资源: 单例模式确保一个类只有一个实例,减少内存开销,节约系统资源。
-
全局访问: 提供全局访问点,方便在不同的组件中共享实例。
-
控制实例数量: 避免了多个实例带来的数据不一致性问题。
2. 适用场景
全局变量、状态管理、共享资源、缓存、日志记录、数据库连接、全局Loading等。
3. 实现方法
构造函数、类的静态属性、闭包。
// 类的静态属性
class Singleton {// 在类中添加一个私有静态成员变量用于保存单例实例private static instance: Singleton// 将类的构造函数设为私有。 类的静态方法仍能调用构造函数,但是其他对象不能调用private constructor() {}// 声明一个公有静态构建方法用于获取单例实例public static getInstance(): Singleton {return this.instance || (this.instance = new Singleton())}
}
// 构造函数
function Singleton() {}Singleton.getInstance = function () {if (!Singleton.instance) {Singleton.instance = new Singleton()}return Singleton.instance
}const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()
console.log(s1 === s2);
class Singleton {static getInstance() {if(!Singleton.instance) {Singleton.instance = new Singleton()}return Singleton.instance}
}const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()
console.log(s1 === s2); // true// 也可以基于 constructor(虽然不标准化,但本质都是一样的)
class Singleton {constructor() {if (!Singleton.instance) {Singleton.instance = this}return Singleton.instance}
}
const s1 = new Singleton()
const s2 = new Singleton()
console.log(s1 === s2); // true
// 闭包实现
Singleton.getInstance = (function () {let instancereturn function () {if (!instance) {instance = new Singleton()}return instance}
})()
4. 经典示例
localStorage
function StorageBase() {}
StorageBase.prototype.getItem = function(key) {return this[key]
}
StorageBase.prototype.setItem = function (key, value) {this[key] = value
}var Storage = (function () {var instance = nullreturn function () {return instance || (instance = new StorageBase())}
})()// 这里用不用new无所谓
var s1 = new Storage()
var s2 = new Storage()console.log(s1 === s2); // true
s1.setItem('a', 1)
console.log(s1.getItem('a')); // 1
console.log(s2.getItem('a')); // 1
class Storage {static instance = nullstatic getInstance = function () {return this.instance || (this.instance = new Storage())}getItem(key) {return this[key]}setItem(key, value) {this[key] = value}
}const s1 = Storage.getInstance()
const s2 = Storage.getInstance()console.log(s1 === s2); // true
s1.setItem('a', 1)
console.log(s1.getItem('a')); // 1
console.log(s2.getItem('a')); // 1
message 弹框
模态框/弹窗管理器:确保在同一时间只有一个模态框或弹窗处于打开状态。
// html
<div><button class="add">add</button><button class="close">close</button>
</div>// js
class Model {static instancestatic getInstance () {if (!this.instance) {const model = document.createElement('div')model.id = 'model'model.style.display = 'none'model.innerHTML = 'here! i am here!'document.body.appendChild(model)this.instance = new Model(model)}return this.instance}constructor(model) {this.model = model}open() {this.model.style.display = 'block'}close() {this.model.style.display = 'none'}
}const addBtn = document.querySelector('.add')
addBtn.addEventListener('click', () => {const model = Model.getInstance()model.open()
})const closeBtn = document.querySelector('.close')
closeBtn.addEventListener('click', () => {const model = Model.getInstance()model.close()
})
import Vue from 'vue'
import { Message } from 'element-ui'
import type { ElMessageOptions, ElMessageComponent } from 'element-ui/types/message'class SingletonMessage {static instance: ElMessageComponent | null = nullprivate constructor() {throw new Error('class SingletonMessage can not be called by new')}static show(options: string | ElMessageOptions) {if (this.instance) returnlet config: ElMessageOptionsif (typeof options === 'string') {config = {message: options,onClose: () => {this.instance = null}}} else {const { onClose, ...otherOptions } = optionsconfig = {...otherOptions,onClose: (...args) => {typeof onClose === 'function' && onClose.apply(this, args)this.instance = null}}}this.instance = Message(config)}static close() {this.instance && this.instance.close()}
}Vue.prototype.$singletonMessage = SingletonMessage
我们在axios的拦截器使用
const SingletonMessage = Vue.prototype.$singletonMessageaxios.interceptors.response.use(res => res,err => {SingletonMessage.show({type: 'error',....})return Promise.reject(err)}
)
ESM 模块化
在 ES6 新增语法的 Module 模块特性,通过 import/export 导出模块中的变量是单例的。
// index.html
<script type="module">
import './single.js'
import './single.js'console.log(obj === obj2) // true
</script>// single.js
console.log('modeule test exec :>> ');
在上面代码中,import 引入的模块是会自动执行的,重复引入一个模块并不会执行多次。
如果我们在当前模块修改了某个导出变量。别的模块再引入会是改变后(实时)的值。如果多个模块都引入该变量,则容易出现莫名问题且不好排查。因此我们尽量不要去改变导出变量的值。
**总结:**单例模式本质核心点在于把之前生成的实例缓存起来。缓存的方式有很多种(类静态属性、闭包等),再对外提供一个访问该缓存实例的接口。
三、简单工厂模式
简单工厂模式 又叫 静态工厂模式 ,由一个工厂对象决定创建某一种产品对象类的实例,主要用来创建同一类对象。
1. 模式特点
优点:工厂类中包含了需要创建哪个品种的产品的判断,使用的时候可以直接根据参数创建对应的产品。不需要知道具体产品的类名,只需要知道创建所用的参数即可。
缺点:
-
扩展困难。一旦增加了新的产品,就需要去修改工厂的逻辑,在产品类型较多的时候,会造成工厂过于复杂,增加维护和扩展的难度。
-
简单工厂模式使用了 static 方法,这样就没有办法通过继承来形成一个阶级结构。
2. 经典示例
工厂上需要有一个静态方法,通过参数去创建这个参数对应的工厂实例。
function createCar(make, model) {return {make: make,model: model,start: function() {console.log(`${make} ${model} is starting.`);},stop: function() {console.log(`${make} ${model} is stopping.`);}};
}const car1 = createCar('Toyota', 'Camry');
const car2 = createCar('Honda', 'Accord');car1.start(); // 输出: Toyota Camry is starting.
car2.stop(); // 输出: Honda Accord is stopping.
class Product {constructor(name) {this.name = name;}
}class Factory {createProduct(name) {return new Product(name);}
}// 使用示例
const factory = new Factory();
const product = factory.createProduct('test');
console.log(product.name); // 输出:test
四、工厂方法模式
工厂方法模式引入了一个抽象工厂,通过继承或实现接口来创建对象。
**示例:**假设我们有一个生产汽车的公司,可以生产轿车、货车和客车。为了生产这些不同类型的汽车,我们需要设计三个工厂:轿车工厂、货车工厂和客车工厂。这三个工厂都实现了一个名为 CarFactory
的接口,该接口定义了创建汽车的方法 createCar()
。
// 定义产品接口
class Car {constructor(name) {this.name = name;}getName() {return this.name;}
}// 定义轿车产品
class SedanCar extends Car {constructor() {super('Sedan Car');}
}// 定义货车产品
class TruckCar extends Car {constructor() {super('Truck Car');}
}// 定义客车产品
class BusCar extends Car {constructor() {super('Bus Car');}
}// 定义工厂接口
class CarFactory {createCar() {throw new Error('createCar method must be implemented.');}
}// 定义轿车工厂
class SedanCarFactory extends CarFactory {createCar() {return new SedanCar();}
}// 定义货车工厂
class TruckCarFactory extends CarFactory {createCar() {return new TruckCar();}
}// 定义客车工厂
class BusCarFactory extends CarFactory {createCar() {return new BusCar();}
}// 使用工厂方法创建汽车
let sedanFactory = new SedanCarFactory();
let sedanCar = sedanFactory.createCar();
console.log(sedanCar.getName()); // Sedan Carlet truckFactory = new TruckCarFactory();
let truckCar = truckFactory.createCar();
console.log(truckCar.getName()); // Truck Carlet busFactory = new BusCarFactory();
let busCar = busFactory.createCar();
console.log(busCar.getName()); // Bus Car
五、抽象工厂模式
抽象工厂模式是一种使用工厂对象来创建一系列相关对象的设计模式。它通过提供一个共同的接口来创建一组相关或相互依赖的对象,而不需要指定具体的类。
抽象工厂模式的核心思想是将对象的创建与使用分离开来。通过抽象工厂函数定义一个接口,具体工厂函数实现这个接口,并负责创建具体的产品对象。客户端代码只与抽象工厂函数和抽象产品对象进行交互,而不需要了解具体的产品对象是如何创建的。
抽象工厂模式的优点之一是它能够提供灵活的对象创建机制。通过定义不同的具体工厂函数,我们可以根据需求创建不同类型或变种的产品对象,而无需修改原有代码。抽象工厂模式还可以隐藏具体产品对象的实现细节,只提供一个统一的接口给客户端使用。
抽象工厂本身不直接创建具体的对象,而是通过具体的工厂子类来创建一组相关的对象。
在JavaScript中,抽象工厂模式通常由以下组件组成:
-
抽象工厂函数: 由一个函数定义,并负责定义一组抽象产品对象的接口。它可以是一个普通的函数,也可以是一个构造函数。
-
具体工厂函数: 由一个函数定义,并负责创建具体产品对象,实现了抽象工厂的接口。具体工厂函数通常使用原型继承或对象字面量来实现。
-
抽象产品对象: 由一个普通对象或原型对象定义,并负责定义产品对象的接口。抽象产品对象通常定义了一组共同的方法或属性。
-
具体产品对象: 由一个普通对象或原型对象定义,并实现了抽象产品对象的接口。具体产品对象通常是根据抽象产品对象定义的模板创建的具体实例。
抽象工厂模式的主要思路是通过抽象工厂函数定义的接口来创建具体的产品对象,这样可以实现对象的解耦和灵活性。客户端代码只需关注抽象工厂函数和抽象产品对象,从而实现了高度的可扩展性和可维护性。
1. 适用场景
-
当有多个相关的对象需要创建,并且这些对象之间有一定的约束关系时,可以使用抽象工厂模式统一创建这些对象。
-
当希望通过一个统一的接来创建一组相关对象时,可以使用抽象工厂模式。
不过,抽象工厂模式也有一些限制和注意事项:
-
抽象工厂模式增加了系统的复杂性,因为它引入了多个抽象类和多个具体类。
-
当需要新增一种产品时,需要同时修改抽象工厂接口和具体工厂实现,这可能会影响到系统的稳定性。
-
抽象工厂模式难以支持新类型的产品的变化,因为它的设计侧重于一类产品。
在实际使用抽象工厂模式的过程中,我们需要根据具体的业务需求和系统架构来判断是否适合采用。它可以帮助我们实现代码的解耦和灵活性,但也需要权衡其可能引入的复杂性和代码的维护成本。
// 定义抽象产品类
class Animal {constructor(name, age) {if (new.target === Animal) {throw new Error("抽象类不能直接实例化");}this.name = name;this.age = age;}eat() {throw new Error("抽象方法不能直接调用");}
}// 定义具体产品类
class Dog extends Animal {constructor(name, age, breed) {super(name, age);this.breed = breed;}eat() {console.log(`${this.name} is eating bones.`);}bark() {console.log(`${this.name} is barking.`);}
}class Cat extends Animal {constructor(name, age, color) {super(name, age);this.color = color;}eat() {console.log(`${this.name} is eating fish.`);}meow() {console.log(`${this.name} is meowing.`);}
}// 定义抽象工厂类
class AnimalFactory {createAnimal() {throw new Error("抽象方法不能直接调用");}
}// 定义具体工厂类
class DogFactory extends AnimalFactory {createAnimal(name, age, breed) {return new Dog(name, age, breed);}
}class CatFactory extends AnimalFactory {createAnimal(name, age, color) {return new Cat(name, age, color);}
}// 使用工厂方法模式创建对象
const dogFactory = new DogFactory();
const dog = dogFactory.createAnimal("Max", 3, "Bulldog");
dog.eat();
dog.bark();const catFactory = new CatFactory();
const cat = catFactory.createAnimal("Luna", 2, "Black");
cat.eat();
cat.meow();
在上述示例中,我们定义了一个抽象产品类 Animal,其中包含一个抽象方法 eat。然后我们定义了具体的产品类 Dog 和 Cat,它们都继承自 Animal,并实现了 eat 方法。接着,我们定义了一个抽象工厂类 AnimalFactory,其中包含一个抽象方法 createAnimal。最后,我们定义了具体的工厂类 DogFactory 和 CatFactory,它们都继承自 AnimalFactory,并实现了 createAnimal 方法,用于创建具体的产品。
2. 经典示例
UI组件库
在开发大型的 UI 组件库时,工厂模式可以用于创建各种类型的 UI 组件,通过工厂来统一管理组件的创建和初始化。
class Button {constructor(text) {this.text = text;}render() {console.log(`<button>${this.text}</button>`);}
}class Input {constructor(type) {this.type = type;}render() {console.log(`<input type="${this.type}"/>`);}
}class UIComponentFactory {createComponent(type, options) {switch (type) {case 'button':return new Button(options.text);case 'input':return new Input(options.type);default:throw new Error('Invalid component type.');}}
}const uiFactory = new UIComponentFactory();const button = uiFactory.createComponent('button', { text: 'Click me' });
const input = uiFactory.createComponent('input', { type: 'text' });button.render(); // 输出: <button>Click me</button>
input.render(); // 输出: <input type="text"/>
插件系统
在构建插件化的应用程序时,工厂模式可以用于动态创建和加载插件。
class Plugin {constructor(name) {this.name = name;}execute() {console.log(`${this.name} plugin is executing.`);}
}class PluginFactory {createPlugin(name) {return new Plugin(name);}
}class App {constructor() {this.plugins = [];this.pluginFactory = new PluginFactory();}loadPlugin(name) {const plugin = this.pluginFactory.createPlugin(name);this.plugins.push(plugin);}runPlugins() {this.plugins.forEach(plugin => plugin.execute());}
}const app = new App();
app.loadPlugin('Analytics');
app.loadPlugin('Logger');
app.runPlugins();
模块化加载
在模块化加载的应用中,工厂模式可以用于创建和管理模块实例。
class Module {constructor(name) {this.name = name;}execute() {console.log(`${this.name} module is executing.`);}
}class ModuleFactory {createModule(name) {return new Module(name);}
}class ModuleManager {constructor() {this.modules = [];this.moduleFactory = new ModuleFactory();}loadModule(name) {const module = this.moduleFactory.createModule(name);this.modules.push(module);}runModules() {this.modules.forEach(module => module.execute());}
}const moduleManager = new ModuleManager();
moduleManager.loadModule('Authentication');
moduleManager.loadModule('Storage');
moduleManager.runModules();
三者的特点:
设计模式 | 异同点 | 适用场景 |
---|---|---|
简单工厂模式 | (Simple Factory Pattern | 通过一个一个的工厂类(即简单工厂)来创建所有的产品对象。只需要调用工厂类的静态方法,传入相应的参数即可获取特定类型的对象。 |
工厂方法模式 | (Factory Pattern) | 将对象的创建延迟到具体的子类工厂中,具体的子工厂实现这个方法来创建不同类型的对象。每个具体的子类工厂负责创建一种具体的产品对象。 |
抽象工厂模式 | (Abstract Factory Pattern) | 抽象工厂定义一个接口,该接口声明了一组可以创建不同类型对象的抽象方法。具体的工厂则实现这个接口,并负责创建一组相关的具体产品对象,通过抽象工厂的方法来创建不同类型的产品对象。 |
六、建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式,旨在将对象的创建过程与其表示相互分离。它允许我们连续地构建对象,逐步设置其属性,然后获取最终的构建结果。使用建造者模式,我们可以按照自己的需求构建对象,而不必关心对象的创建过程和内部细节。
可以将一个复杂的对象分解成多个简单的对象来进行构建,将复杂的构建层与表现层分离,使相同的构建过程可以创建不同的表示模式。
建造者模式通常包含以下几个角色:
-
Director(指挥者): 负责定义构建过程的顺序和逻辑,控制对象的创建过程。它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
-
Builder(抽象建造者): 负责实际构建复杂对象的接口,定义了创建对象的每个步骤。它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
-
ConcreteBuilder(具体建造者): 实现 Builder 接口,实际进行对象的构建。完成复杂产品的各个部件的具体创建方法。
-
Product(产品角色): 表示最终构建完成的对象。它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
1. 模式特点
建造者模式的优点:
-
**灵活性高:**建造者模式允许逐步构建复杂对象,并且可以根据需求自由选择和配置对象的属性,而不需要关心对象的创建过程和内部细节。
-
**代码可读性好:**通过将对象的构建过程封装在建造者类中,代码更加清晰直观。建造者模式提供了一种结构化的方式来创建对象,使得代码易于理解和维护。
-
**创建不可变对象:**通过将对象的属性设置为私有,并提供相应的 getter 方法,可以确保对象在创建后不会被修改,增加对象的安全性和封装性。
-
**代码复用性高:**可以将复杂对象构建的逻辑封装在建造者类中,以便在同一场景下复用。
当然,任何一件事物并不是只有优点没有缺点,当然建造者模式也是有一定的缺点的。
-
增加代码量: 引入建造者模式会增加一些额外的类和方法,这可能导致代码量的增加。有时候,如果只需要简单的对象,使用建造者模式可能会过于繁琐。
-
对象构建过程不够灵活: 建造者模式在创建对象时要按照一定的顺序和一系列步骤。这可能会限制构建过程的灵活性,不够适应某些特殊情况。
-
可能存在建造者类过多: 当对象有很多属性时,可能需要创建多个建造者类来构建对象。这可能会导致建造者类的增加,给代码的维护和理解带来一定的复杂性。
2. 一般流程
定义产品类: 首先,需要定义一个产品类,它是由多个部分组成的复杂对象。产品类通常具有多个属性和方法。
创建建造者类: 建造者类负责实际构建产品对象。它提供了一系列方法来设置产品的不同属性。
设置产品属性方法: 建造者类中的方法用于设置产品的属性。每个方法通常设置一个特定的属性,并返回建造者对象本身,以便支持方法链式调用。
构建产品方法: 当所有属性设置完毕后,建造者类提供一个构建产品的方法。该方法执行实际的构建过程,将属性组装成最终的产品对象。
创建指导者类(可选): 在某些情况下,可以创建一个指导者类来协调建造者的构建过程。指导者类知道构建的顺序和方式,并且负责按照正确的顺序调用建造者的方法。
客户端使用: 客户端代码通过实例化建造者对象,并使用建造者对象的方法来设置产品的属性。最后,通过调用建造者对象的构建产品方法,获取构建完成的产品对象。
3. 适用场景
1、需要生成的对象具有复杂的内部结构。
2、需要生成的对象内部属性本身相互依赖。
4. 经典示例
案例场景一
假设我们正在开发一个游戏,需要构建一种特殊类型的角色:骑士。骑士有许多属性,包括名字、等级、武器、盔甲等。
首先,我们定义一个角色类,用于表示骑士对象:
class Knight {constructor(name, level, weapon, armor) {this.name = name;this.level = level;this.weapon = weapon;this.armor = armor;}toString() {return `${this.name}, ${this.level}, weapon: ${this.weapon}, armor: ${this.armor}`;}
}
然后,我们定义一个骑士建造者类,用于逐步构建骑士对象:
class KnightBuilder {constructor() {this.name = null;this.level = null;this.weapon = null;this.armor = null;}// 名称setName(name) {this.name = name;return this;}// 等级setLevel(level) {this.level = level;return this;}// 武器setWeapon(weapon) {this.weapon = weapon;return this;}// 盔甲setArmor(armor) {this.armor = armor;return this;}// 构造骑士build() {return new Knight(this.name, this.level, this.weapon, this.armor);}
}
在这个例子,我们定义了一个KnightBuilder类它包含了与骑士对象相关的各种属性我们可以使用该建造者类逐步设置这些属性,最终通过调用 build 方法来获取建完成的骑士对象。
接下来,让我们使用建造者模式来构建一个骑士对象:
const knight = new KnightBuilder().setName("Arthur").setLevel(10).setWeapon("Excalibur").setArmor("Plate").build();console.log(knight.toString());
在这个例子中,我们首先创建了一个 KnightBuilder 实例,并逐步设置了骑士对象的各个属性。
最后,通过调用 build 方法,我们获取到了构建完成的骑士对象并打印出来。输出结果为:
Arthur, Level 10, weapon: Excalibur, armor: Plate
**总结:**正如我们所看到的,通过建造者模式,我们可以在不污染对象类的情况下,方便地构建出具有各种属性的骑士对象。
案例场景二
假设我们正在构建一个汽车对象,并且汽车具有一些复杂的属性。
class Car {constructor() {this.brand = null;this.color = null;this.engine = null;}
}class CarBuilder {constructor() {this.car = new Car();}// 品牌setBrand(brand) {this.car.brand = brand;return this;}// 颜色setColor(color) {this.car.color = color;return this;}// 引擎setEngine(engine) {this.car.engine = engine;return this;}build() {return this.car;}
}// 创建汽车对象示例
const car = new CarBuilder().setBrand("Tesla").setColor("Red").setEngine("Electric").build();console.log(car);
案例场景三
构建一个在线订餐平台时,我们需要处理各种不同的订单项,包括不同类型的菜品、饮料以及可能的特别要求。订单构建过程需要灵活地适应不同的定制选项。
// 订单项接口
interface OrderItem {void prepare();}// 具体订单项实现
class Meal implements OrderItem {private String dishType;private int quantity;private List<String> toppings;// Constructor, getters and setterspublic void prepare() {// 准备餐点逻辑}
}class Beverage implements OrderItem {private String drinkType;private String size;private boolean ice;// Constructor, getters and setterspublic void prepare() {// 准备饮料逻辑}
}// 订单建造者
class OrderBuilder {private List<OrderItem> orderItems = new ArrayList<>();private String deliveryTime;public OrderBuilder addOrderItem(OrderItem item) {orderItems.add(item);return this;}public OrderBuilder setDeliveryTime(String time) {this.deliveryTime = time;return this;}public Order build() {Order order = new Order();order.setOrderItems(orderItems);order.setDeliveryTime(deliveryTime);return order;}
}// 订单类
class Order {private List<OrderItem> orderItems;private String deliveryTime;// Constructor, getters and setters// 准备订单中的所有项public void prepareOrder() {for (OrderItem item : orderItems) {item.prepare();}}
}// 客户端使用建造者模式构建订单
public class OrderSystem {public static void main(String[] args) {Order order = new OrderBuilder().addOrderItem(new MealBuilder().setDishType("牛肉面").setQuantity(2).addTopping("香菜").build()).addOrderItem(new BeverageBuilder().setDrinkType("可乐").setSize("大杯").addIce(true).build()).setDeliveryTime("12:00").build();order.prepareOrder();}
}
案例场景四
假设我们需要创建一个包含多个输入字段和验证规则的表单。适用建造者模式可以将表单的构建过程分解为多个步骤,每个步骤负责添加一个字段和相应的验证规则。这样一来,我们可以根据需要自由组合字段和验证规则,而不需要关心具体的构建细节。
// 表单建造者
class FormBuilder {constructor() {this.fields = [];}addField(label, type, required) {this.fields.push({ label, type, required });return this;}addValidation(validationFn) {const field = this.fields[this.fields.length - 1];field.validation = validationFn;return this;}build() {return new Form(this.fields);}
}class Form {constructor(fields) {this.fields = fields;}validate() {for (const field of this.fields) {if (field.required && !field.value) {return false;}if (field.validation && !field.validation(field.value)) {return false;}}return true;}
}// 使用建造者模式创建表单
const form = new FormBuilder().addField("Username", "text", true).addValidation(value => value.length >= 6).addField("Password", "password", true).addValidation(value => value.length >= 8).build();// 验证表单
if (form.validate()) {console.log("Form is valid");
} else {console.log("Form is invalid");
}
案例场景五
在前端开发中,我们经常要构建复杂的UI组件,其中包含多个子组件和配置选项。使用建造者模式可以将组件的构建过程分解为多个步骤,每个步骤负责添加一个子组件或者配置选项。这样一来,我们可以根据需要自由组合子组件和配置选项,而不需要关心具体的构建细节。
class ComponentBuilder {constructor() {this.children = [];this.props = {};}addChild(child) {this.children.push(child);return this;}setProps(props) {this.props = props;return this;}build() {return new Component(this.children, this.props);}
}class Component {constructor(children, props) {this.children = children;this.props = props;}render() {// 渲染组件}
}// 使用建造者模式构建复杂的UI组件
const component = new ComponentBuilder().addChild(new ChildComponent1()).addChild(new ChildComponent2()).setProps({ color: "red", size: "large" }).build();// 渲染组件
component.render();