Simple Factory Pattern

使用工厂函数统一创建不同类型的对象

问题

什么是简单工厂模式?如何在 JavaScript 中实现?

解答

简单工厂模式通过一个工厂函数,根据传入的参数决定创建哪种类型的对象,将对象的创建逻辑集中管理。

基础实现

// 产品类
class Car {
  constructor(name) {
    this.name = name;
    this.type = 'car';
  }
  drive() {
    console.log(`${this.name} is driving`);
  }
}

class Bike {
  constructor(name) {
    this.name = name;
    this.type = 'bike';
  }
  ride() {
    console.log(`${this.name} is riding`);
  }
}

// 简单工厂
function createVehicle(type, name) {
  switch (type) {
    case 'car':
      return new Car(name);
    case 'bike':
      return new Bike(name);
    default:
      throw new Error(`Unknown vehicle type: ${type}`);
  }
}

// 使用
const myCar = createVehicle('car', 'Tesla');
const myBike = createVehicle('bike', 'Giant');

myCar.drive();  // Tesla is driving
myBike.ride();  // Giant is riding

使用对象映射优化

// 产品类注册表
const vehicleClasses = {
  car: Car,
  bike: Bike,
};

// 工厂函数
function createVehicle(type, ...args) {
  const VehicleClass = vehicleClasses[type];
  if (!VehicleClass) {
    throw new Error(`Unknown vehicle type: ${type}`);
  }
  return new VehicleClass(...args);
}

// 支持动态注册新类型
function registerVehicle(type, VehicleClass) {
  vehicleClasses[type] = VehicleClass;
}

// 注册新类型
class Truck {
  constructor(name) {
    this.name = name;
  }
}
registerVehicle('truck', Truck);

const myTruck = createVehicle('truck', 'Volvo');

实际应用:UI 组件工厂

// 不同类型的弹窗组件
class AlertDialog {
  constructor(options) {
    this.title = options.title;
    this.message = options.message;
  }
  render() {
    return `<div class="alert">${this.message}</div>`;
  }
}

class ConfirmDialog {
  constructor(options) {
    this.title = options.title;
    this.onConfirm = options.onConfirm;
    this.onCancel = options.onCancel;
  }
  render() {
    return `<div class="confirm">${this.title}<button>确定</button><button>取消</button></div>`;
  }
}

class PromptDialog {
  constructor(options) {
    this.title = options.title;
    this.placeholder = options.placeholder || '';
  }
  render() {
    return `<div class="prompt"><input placeholder="${this.placeholder}"/></div>`;
  }
}

// 弹窗工厂
const dialogTypes = {
  alert: AlertDialog,
  confirm: ConfirmDialog,
  prompt: PromptDialog,
};

function createDialog(type, options) {
  const DialogClass = dialogTypes[type];
  if (!DialogClass) {
    throw new Error(`Unknown dialog type: ${type}`);
  }
  return new DialogClass(options);
}

// 使用
const alert = createDialog('alert', { message: '操作成功' });
const confirm = createDialog('confirm', { 
  title: '确认删除?',
  onConfirm: () => console.log('confirmed'),
});

关键点

  • 封装创建逻辑:调用方无需知道具体类,只需传入类型参数
  • 用对象映射替代 switch:便于扩展,支持动态注册新类型
  • 适用场景:创建对象种类有限且相对固定,如 UI 组件、数据解析器
  • 缺点:新增类型需修改工厂(违反开闭原则),复杂场景考虑抽象工厂模式
  • 与构造函数区别:工厂可返回不同类型实例,构造函数只能返回自身实例