一、当JavaScript遇见TypeScript

我永远记得三年前重构那个电商项目时,满屏的any类型和console.log调试的痛苦经历。当我们决定引入TypeScript时,团队就像拿到了代码世界的防撞条和指南针。TypeScript的接口系统就像是给原本松散的数据结构穿上了合身的西服,而类的引入让我们的业务实体终于有了家族族谱。

1.1 接口:你的代码说明书

来看看这个商品模型的演变过程:

// TypeScript 技术栈
interface IProduct {
  id: number;
  name: string;
  price: number;
  getDiscountPrice?(discount: number): number; // 可选方法
}

// 实现类
class Book implements IProduct {
  constructor(
    public id: number,
    public name: string,
    public price: number,
    public author: string  // 扩展属性
  ) {}

  // 必须实现接口定义的getDiscountPrice
  getDiscountPrice(discount: number): number {
    return this.price * (discount > 0.5 ? 0.5 : discount); // 最高5折的限制
  }
}

// 验证示例
const designPatternBook = new Book(1, '设计模式解析', 99, '某大牛');
console.log(designPatternBook.getDiscountPrice(0.6)); // 输出49.5

这段代码就像给书籍商品装上了标准化的零件,类型检查会在编译时揪出所有不符合规格的"假冒伪劣品",团队协作时接口文档甚至可以直接生成API文档。

1.2 类的进阶玩法

我们的购物车系统通过类继承实现了优惠策略:

abstract class DiscountStrategy {
  abstract calculate(price: number): number;
  
  // 模板方法
  applyDiscount(price: number): number {
    const discounted = this.calculate(price);
    return discounted > 0 ? discounted : 0;
  }
}

class MemberDiscount extends DiscountStrategy {
  constructor(private level: number) {
    super();
  }

  calculate(price: number): number {
    return price * (1 - this.level * 0.1); // 会员等级对应折扣
  }
}

// 用法示例
const vipDiscount = new MemberDiscount(3); // 三级会员7折
console.log(vipDiscount.applyDiscount(100)); // 输出70

这种设计就像建造乐高积木,基础策略是底板,具体的优惠算法是各种形状的积木块。当我们需要新增促销类型时,继承这个抽象类就能保证所有优惠策略都有相同的操作接口。

二、抽象工厂模式实战

去年双十一大促时,我们的商品展示模块需要根据不同客户群体展示不同的商品组合。当if-else分支超过十个时,我们意识到该用设计模式重构了。

2.1 搭建模具体系

定义完整的电子商品生产流水线:

// 核心接口体系
interface DeviceFactory {
  createPhone(): IPhone;
  createLaptop(): ILaptop;
}

interface IPhone {
  makeCall(): void;
  getCameraSpec(): string;
}

interface ILaptop {
  startOS(): void;
  getBatteryLife(): number;
}

// 旗舰设备工厂
class FlagshipFactory implements DeviceFactory {
  createPhone(): IPhone {
    return new GalaxyUltra();
  }

  createLaptop(): ILaptop {
    return new Alienware();
  }
}

// 具体产品实现
class GalaxyUltra implements IPhone {
  makeCall() {
    console.log('使用卫星通信拨打电话');
  }

  getCameraSpec() {
    return '200MP主摄 + 10倍光学变焦';
  }
}

class Alienware implements ILaptop {
  startOS() {
    console.log('RGB灯效启动中...进入游戏模式');
  }

  getBatteryLife() {
    return 2.5; // 小时
  }
}

2.2 客户端如何开车

用户界面根据用户画像选择工厂:

class DeviceStore {
  constructor(private factory: DeviceFactory) {}

  showDeviceCombo() {
    const phone = this.factory.createPhone();
    const laptop = this.factory.createLaptop();

    console.log('🏷️ 推荐搭配:');
    console.log(`📱 手机特性: ${phone.getCameraSpec()}`);
    console.log(`💻 笔记本续航: ${laptop.getBatteryLife()}小时`);
    
    laptop.startOS();
    phone.makeCall();
  }
}

// 根据不同场景切换工厂
const gameStore = new DeviceStore(new FlagshipFactory());
gameStore.showDeviceCombo();

/* 输出:
🏷️ 推荐搭配:
📱 手机特性: 200MP主摄 + 10倍光学变焦
💻 笔记本续航: 2.5小时
RGB灯效启动中...进入游戏模式
使用卫星通信拨打电话
*/

这种模式就像组装宜家家具,工厂是那份包含所有零件的清单。当需要为家庭用户推荐平价套装时,我们只需要换个BudgetFactory就能生成完全不同的产品组合。

三、模式应用的十字路口

在物流管理系统中,我们曾尝试用这个模式处理不同快递公司的对接。顺丰和京东的运单生成、运费计算接口差异,被完美封装在不同的工厂实现中。新接入极兔速递时,开发时间从三天缩短到半天。

3.1 那些年踩过的坑

刚接触抽象工厂时,我犯过一个典型错误:给所有工厂都添加了createSmartWatch方法,结果有家合作厂商根本不生产智能手表。后来我们用组合模式解耦产品系列,终于不再强迫工厂生产它们不擅长的产品。

3.2 性能与可维护性的较量

在物联网设备管理中,我们测试过三种方案:

  • 直接实例化:启动快但维护难
  • 简单工厂:易维护但扩展性差
  • 抽象工厂:初始化耗时多0.5ms但支持动态切换

最终的压测数据显示,在1000次连续创建的场景下,抽象工厂的内存控制表现最优,因为可以集中管理同类产品的资源分配。

四、现代前端框架中的模式进化

在React项目中发现,Context API配合抽象工厂可以创造神奇的效果:

// 创建主题工厂上下文
const ThemeContext = React.createContext<ThemeFactory>(new LightThemeFactory());

// 在组件中使用
const Button: React.FC = () => {
  const factory = useContext(ThemeContext);
  
  const buttonStyle = factory.createButtonStyle();
  const icon = factory.createIcon();

  return (
    <button style={buttonStyle}>
      {icon} 点击我
    </button>
  );
};

这种实践让我们的主题切换变得像换衣服一样简单,黑暗模式和节日主题的实现完全隔离,再也不用担心不同主题的样式互相污染。

五、模式选择的红绿灯

最近为跨境电商项目设计支付系统时,我们面临的关键选择:

  1. 需要支持PayPal、Stripe、Alipay等支付方式
  2. 每种支付方式都有不同的验证规则
  3. 订单退款流程存在显著差异

使用抽象工厂模式后,支付流程的控制代码缩减了40%,新增一个支付渠道的工时从3人日降为0.5人日。特别是在处理沙特本地支付方案时,工厂模式帮我们隔离了复杂的宗教节日结算规则。

六、写在最后:架构的哲学思考

从JavaScript的动态美学到TypeScript的结构之美,抽象工厂模式教会我们最重要的不是代码怎么写,而是如何用接口搭建起组件之间的桥梁。在最近一次的微服务改造中,我们甚至把这种模式应用到了服务网格的配置管理中心,让不同环境的服务发现机制可以通过切换工厂来灵活配置。

每个模式都是特定场景下的最优解,就像脚手架不能用来造摩天轮。当你的项目中开始出现"套餐式"的对象组合需求时,就是时候考虑抽象工厂模式了。记住,好的架构不是设计出来的,而是在不断的重构中自然生长出来的。