3. 抽象工厂模式(Abstract Factory)

问题:需要创建一整套相关对象(比如不同风格的 UI 组件)。

核心:在工厂方法的基础上再抽象一层,一个工厂负责生产一套产品。

interface Renderable {
  render(): string;
}

interface UIFactory {
  createButton(): Renderable;
  createInput(): Renderable;
}

class LightFactory implements UIFactory {
  createButton(): Renderable { return { render: () => '浅色按钮' }; }
  createInput(): Renderable  { return { render: () => '浅色输入框' }; }
}

class DarkFactory implements UIFactory {
  createButton(): Renderable { return { render: () => '深色按钮' }; }
  createInput(): Renderable  { return { render: () => '深色输入框' }; }
}

type Theme = 'light' | 'dark';

function createUI(theme: Theme): UIFactory {
  const factories: Record<Theme, new () => UIFactory> = {
    light: LightFactory,
    dark: DarkFactory,
  };
  return new factories[theme]();
}

const ui = createUI('dark');
console.log(ui.createButton().render()); // 深色按钮
package abstractfactory

import "fmt"

type Button interface{ Render() string }
type Input interface{ Render() string }

type UIFactory interface {
  CreateButton() Button
  CreateInput() Input
}

// 浅色
type LightButton struct{}
func (b LightButton) Render() string { return "浅色按钮" }

type LightInput struct{}
func (i LightInput) Render() string { return "浅色输入框" }

type LightFactory struct{}
func (f LightFactory) CreateButton() Button { return LightButton{} }
func (f LightFactory) CreateInput() Input   { return LightInput{} }

// 深色
type DarkButton struct{}
func (b DarkButton) Render() string { return "深色按钮" }

type DarkInput struct{}
func (i DarkInput) Render() string { return "深色输入框" }

type DarkFactory struct{}
func (f DarkFactory) CreateButton() Button { return DarkButton{} }
func (f DarkFactory) CreateInput() Input   { return DarkInput{} }

func NewUIFactory(theme string) (UIFactory, error) {
  switch theme {
  case "light":
    return LightFactory{}, nil
  case "dark":
    return DarkFactory{}, nil
  default:
    return nil, fmt.Errorf("未知主题: %s", theme)
  }
}

实战场景

  • 多主题 UI 套件:浅色主题、深色主题、品牌主题各自产出一整套按钮、输入框、弹窗和卡片,确保视觉风格一致。
  • 跨平台组件:Web、iOS、Android、桌面端都需要“按钮、菜单、对话框”这组组件,抽象工厂可以按平台返回同一族实现。
  • 多数据库适配:不同数据库不只连接方式不同,查询构造器、事务管理器、迁移器也可能是一整套实现。
  • 云厂商切换:对象存储、消息队列、函数计算、日志服务经常按 AWS、GCP、阿里云、Cloudflare 成套切换。
  • 支付国家化:不同国家或地区的支付方式、税费计算、发票生成、退款流程是一组相关对象,适合由地区工厂统一创建。
  • 游戏皮肤包:同一角色需要不同主题下的贴图、音效、粒子和 UI 资源,工厂返回一套风格一致的资源对象。
  • 多租户定制:企业版 SaaS 里,不同租户可能有自己的审批器、权限策略、通知模板和报表导出器。
  • 测试环境套件:集成测试时一次性替换 repository、queue、mailer、storage 为内存实现,避免真实外部依赖。
  • 协议栈组合:HTTP、gRPC、WebSocket 的客户端、请求对象、响应解析器和错误映射通常需要成套出现。
  • 设计系统迁移:旧设计系统和新设计系统并行时,用不同工厂提供同名组件,页面逐步切换而不直接依赖具体实现。