别再硬写if-else了!用JavaScript工厂模式重构你的外卖订单和UI组件代码
用工厂模式重构你的JavaScript代码告别if-else地狱每次看到代码里那些层层嵌套的if-else语句是不是感觉头都大了特别是在处理复杂业务逻辑时比如外卖订单系统或者UI组件库的主题切换条件判断会像野草一样疯长。今天我要分享的是如何用工厂模式来优雅地解决这个问题让你的代码像瑞士军刀一样既锋利又灵活。1. 为什么我们需要工厂模式想象一下你正在开发一个外卖平台。订单类型有餐饮、生鲜、鲜花等等每种订单都有不同的属性和处理逻辑。传统的写法可能是这样的function createOrder(orderType, params) { if (orderType food) { // 处理餐饮订单 return { ...params, tasteNote: params.extraInfo } } else if (orderType fresh) { // 处理生鲜订单 return { ...params, storageRequirement: params.extraInfo } } else if (orderType flower) { // 处理鲜花订单 return { ...params, deliveryTime: params.extraInfo } } // 更多else if... }这种代码有几个明显的问题难以维护每次新增订单类型都要修改这个函数可读性差条件分支太多逻辑不清晰违反开闭原则对扩展开放对修改关闭的原则被破坏工厂模式正是为了解决这些问题而生的。它通过将对象的创建过程封装起来让客户端代码不需要知道具体的创建细节。2. 简单工厂模式实战让我们先用简单工厂模式重构上面的外卖订单系统。简单工厂的核心思想是把对象的创建逻辑集中管理。2.1 订单类定义首先我们定义各种订单类class FoodOrder { constructor(params) { this.orderId params.orderId; this.address params.address; this.tasteNote params.extraInfo; } } class FreshOrder { constructor(params) { this.orderId params.orderId; this.address params.address; this.storageRequirement params.extraInfo; } } class FlowerOrder { constructor(params) { this.orderId params.orderId; this.address params.address; this.deliveryTime params.extraInfo; } }2.2 创建订单工厂然后我们创建订单工厂class OrderFactory { static createOrder(type, params) { switch(type) { case food: return new FoodOrder(params); case fresh: return new FreshOrder(params); case flower: return new FlowerOrder(params); default: throw new Error(未知的订单类型); } } }2.3 使用工厂创建订单现在创建订单变得非常简单const myFoodOrder OrderFactory.createOrder(food, { orderId: 123, address: 北京朝阳区, extraInfo: 少辣多醋 }); const myFreshOrder OrderFactory.createOrder(fresh, { orderId: 456, address: 上海浦东区, extraInfo: 需要冷藏 });简单工厂的优势客户端代码与具体实现解耦创建逻辑集中管理便于维护新增订单类型只需修改工厂类3. 抽象工厂模式进阶当业务变得更加复杂时简单工厂可能就不够用了。比如你的外卖平台现在需要支持不同地区的订单每个地区的订单处理方式可能不同。这时候抽象工厂模式就派上用场了。3.1 抽象工厂模式概念抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。它包含以下几个角色抽象工厂声明创建抽象产品的方法具体工厂实现抽象工厂的方法创建具体产品抽象产品声明产品的接口具体产品实现抽象产品的接口3.2 地区订单系统实现让我们用抽象工厂模式实现一个支持不同地区的外卖订单系统。3.2.1 定义抽象产品// 抽象订单 class AbstractOrder { constructor(params) { if (new.target AbstractOrder) { throw new Error(不能实例化抽象类); } this.orderId params.orderId; this.address params.address; } validate() { throw new Error(必须实现validate方法); } } // 抽象支付 class AbstractPayment { constructor(params) { if (new.target AbstractPayment) { throw new Error(不能实例化抽象类); } this.amount params.amount; } process() { throw new Error(必须实现process方法); } }3.2.2 定义具体产品// 北京地区订单 class BeijingOrder extends AbstractOrder { validate() { console.log(北京订单验证逻辑); // 北京特有的验证逻辑 } } // 上海地区订单 class ShanghaiOrder extends AbstractOrder { validate() { console.log(上海订单验证逻辑); // 上海特有的验证逻辑 } } // 北京地区支付 class BeijingPayment extends AbstractPayment { process() { console.log(北京支付处理逻辑); // 北京特有的支付逻辑 } } // 上海地区支付 class ShanghaiPayment extends AbstractPayment { process() { console.log(上海支付处理逻辑); // 上海特有的支付逻辑 } }3.2.3 定义抽象工厂class AbstractOrderFactory { createOrder(params) { throw new Error(必须实现createOrder方法); } createPayment(params) { throw new Error(必须实现createPayment方法); } }3.2.4 实现具体工厂// 北京工厂 class BeijingOrderFactory extends AbstractOrderFactory { createOrder(params) { return new BeijingOrder(params); } createPayment(params) { return new BeijingPayment(params); } } // 上海工厂 class ShanghaiOrderFactory extends AbstractOrderFactory { createOrder(params) { return new ShanghaiOrder(params); } createPayment(params) { return new ShanghaiPayment(params); } }3.2.5 使用抽象工厂// 根据地区选择工厂 function getRegionFactory(region) { const factories { beijing: BeijingOrderFactory, shanghai: ShanghaiOrderFactory }; const FactoryClass factories[region]; if (!FactoryClass) { throw new Error(不支持该地区); } return new FactoryClass(); } // 创建北京订单 const beijingFactory getRegionFactory(beijing); const order beijingFactory.createOrder({ orderId: 123, address: 北京朝阳区 }); order.validate(); const payment beijingFactory.createPayment({ amount: 100 }); payment.process();抽象工厂的优势确保创建的产品是兼容的同一地区的订单和支付新增地区只需添加新的工厂和产品类不修改现有代码客户端代码与具体产品完全解耦4. UI组件库的主题切换实战让我们再看一个前端开发中常见的场景UI组件库的主题切换。使用抽象工厂模式我们可以优雅地实现这个功能。4.1 定义抽象产品// 抽象按钮 class AbstractButton { render() { throw new Error(必须实现render方法); } } // 抽象输入框 class AbstractInput { render() { throw new Error(必须实现render方法); } }4.2 实现具体产品// 深色主题按钮 class DarkButton extends AbstractButton { render() { return { backgroundColor: #333, color: #fff, border: 1px solid #666 }; } } // 深色主题输入框 class DarkInput extends AbstractInput { render() { return { backgroundColor: #222, color: #fff, border: 1px solid #444 }; } } // 浅色主题按钮 class LightButton extends AbstractButton { render() { return { backgroundColor: #fff, color: #333, border: 1px solid #ddd }; } } // 浅色主题输入框 class LightInput extends AbstractInput { render() { return { backgroundColor: #f9f9f9, color: #333, border: 1px solid #ccc }; } }4.3 定义抽象工厂class AbstractThemeFactory { createButton() { throw new Error(必须实现createButton方法); } createInput() { throw new Error(必须实现createInput方法); } }4.4 实现具体工厂// 深色主题工厂 class DarkThemeFactory extends AbstractThemeFactory { createButton() { return new DarkButton(); } createInput() { return new DarkInput(); } } // 浅色主题工厂 class LightThemeFactory extends AbstractThemeFactory { createButton() { return new LightButton(); } createInput() { return new LightInput(); } }4.5 使用主题工厂// 根据用户偏好选择主题 function getThemeFactory(theme) { const factories { dark: DarkThemeFactory, light: LightThemeFactory }; const FactoryClass factories[theme]; if (!FactoryClass) { throw new Error(不支持该主题); } return new FactoryClass(); } // 使用深色主题 const darkTheme getThemeFactory(dark); const darkButton darkTheme.createButton(); const darkInput darkTheme.createInput(); console.log(darkButton.render()); // 深色按钮样式 console.log(darkInput.render()); // 深色输入框样式 // 切换为浅色主题 const lightTheme getThemeFactory(light); const lightButton lightTheme.createButton(); const lightInput lightTheme.createInput(); console.log(lightButton.render()); // 浅色按钮样式 console.log(lightInput.render()); // 浅色输入框样式主题工厂的优势主题切换变得非常简单确保同一主题下的组件风格一致新增主题只需添加新的工厂和组件类5. 工厂模式的最佳实践在实际项目中应用工厂模式时有几个最佳实践值得注意何时使用简单工厂对象创建逻辑相对简单产品种类有限且不太可能频繁扩展需要快速实现解耦何时使用抽象工厂系统需要独立于其产品的创建、组合和表示系统需要配置多个产品族中的一个需要强调一系列相关产品对象的设计以便进行联合使用想提供一个产品类库但只想显示它们的接口而不是实现性能考虑工厂模式会引入额外的类和对象可能增加系统复杂度在性能敏感的场景要权衡利弊与其它模式的结合工厂方法模式定义一个创建对象的接口但让子类决定实例化哪个类单例模式确保工厂类只有一个实例原型模式通过复制原型对象来创建新对象测试友好性工厂模式使单元测试更容易因为可以轻松替换模拟对象依赖注入框架通常大量使用工厂模式// 示例使用工厂模式进行测试 class MockOrder extends AbstractOrder { validate() { console.log(Mock验证逻辑); return true; // 总是返回验证成功 } } class MockOrderFactory extends AbstractOrderFactory { createOrder(params) { return new MockOrder(params); } createPayment(params) { // 返回mock支付 } } // 在测试中使用mock工厂 const testFactory new MockOrderFactory(); const testOrder testFactory.createOrder({}); testOrder.validate(); // 使用mock实现工厂模式是每个前端开发者工具箱中不可或缺的工具。它能帮助你写出更干净、更可维护的代码特别是在处理复杂对象创建逻辑时。下次当你发现自己在写一大堆if-else语句时不妨停下来想想这里是不是可以用工厂模式来重构