抽象工厂模式

创建一系列相关对象的设计模式实现

问题

什么是抽象工厂模式?如何在 JavaScript 中实现?

解答

抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。

场景示例:跨平台 UI 组件

假设我们需要创建一套 UI 组件,支持不同的主题风格(Light / Dark)。

// 抽象产品:按钮
class Button {
  render() {
    throw new Error('子类必须实现 render 方法');
  }
}

// 抽象产品:输入框
class Input {
  render() {
    throw new Error('子类必须实现 render 方法');
  }
}

// 具体产品:Light 主题按钮
class LightButton extends Button {
  render() {
    return '<button class="btn-light">Light Button</button>';
  }
}

// 具体产品:Light 主题输入框
class LightInput extends Input {
  render() {
    return '<input class="input-light" placeholder="Light Input" />';
  }
}

// 具体产品:Dark 主题按钮
class DarkButton extends Button {
  render() {
    return '<button class="btn-dark">Dark Button</button>';
  }
}

// 具体产品:Dark 主题输入框
class DarkInput extends Input {
  render() {
    return '<input class="input-dark" placeholder="Dark Input" />';
  }
}

// 抽象工厂
class UIFactory {
  createButton() {
    throw new Error('子类必须实现 createButton 方法');
  }
  createInput() {
    throw new Error('子类必须实现 createInput 方法');
  }
}

// 具体工厂:Light 主题工厂
class LightUIFactory extends UIFactory {
  createButton() {
    return new LightButton();
  }
  createInput() {
    return new LightInput();
  }
}

// 具体工厂:Dark 主题工厂
class DarkUIFactory extends UIFactory {
  createButton() {
    return new DarkButton();
  }
  createInput() {
    return new DarkInput();
  }
}

// 使用示例
function renderUI(factory) {
  const button = factory.createButton();
  const input = factory.createInput();
  
  console.log(button.render());
  console.log(input.render());
}

// 切换主题只需更换工厂
const lightFactory = new LightUIFactory();
const darkFactory = new DarkUIFactory();

console.log('--- Light Theme ---');
renderUI(lightFactory);

console.log('--- Dark Theme ---');
renderUI(darkFactory);

简化版:函数式实现

// 工厂函数版本,更符合 JavaScript 风格
const createUIFactory = (theme) => {
  const themes = {
    light: {
      createButton: () => ({
        render: () => '<button class="btn-light">Light Button</button>'
      }),
      createInput: () => ({
        render: () => '<input class="input-light" />'
      })
    },
    dark: {
      createButton: () => ({
        render: () => '<button class="btn-dark">Dark Button</button>'
      }),
      createInput: () => ({
        render: () => '<input class="input-dark" />'
      })
    }
  };
  
  return themes[theme] || themes.light;
};

// 使用
const factory = createUIFactory('dark');
const button = factory.createButton();
console.log(button.render()); // <button class="btn-dark">Dark Button</button>

与工厂模式的区别

// 工厂模式:创建单一产品
class ButtonFactory {
  create(type) {
    if (type === 'light') return new LightButton();
    if (type === 'dark') return new DarkButton();
  }
}

// 抽象工厂:创建一系列相关产品
class UIFactory {
  createButton() { /* ... */ }
  createInput() { /* ... */ }
  createCheckbox() { /* ... */ }
  // 保证产品之间的一致性
}

关键点

  • 解决问题:创建一系列相关对象,保证产品族的一致性
  • 与工厂模式区别:工厂模式创建单一产品,抽象工厂创建产品族
  • 优点:切换产品族只需更换工厂,符合开闭原则
  • 缺点:新增产品类型需要修改所有工厂类
  • 适用场景:主题切换、跨平台 UI、数据库适配层