常用设计模式:工厂方法模式

在软件开发中,对象创建是最基础也是最关键的操作之一。随着项目规模的增长,直接使用 new 关键字创建对象会导致代码高度耦合,难以维护和扩展。工厂方法模式正是为了解决这一问题而生的经典设计模式。

什么是工厂方法模式?

工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪个类。这种模式将对象的实例化推迟到子类,从而实现了创建逻辑与使用逻辑的分离。

核心概念解析

工厂方法模式包含以下几个关键角色:

  • 产品接口(Product Interface):定义了产品对象的通用接口
  • 具体产品(Concrete Products):实现产品接口的具体类
  • 创建者(Creator):声明工厂方法,返回产品对象
  • 具体创建者(Concrete Creators):重写工厂方法,返回具体产品实例

为什么使用工厂方法模式?

解决紧耦合问题

考虑以下紧耦合的代码:

typescript 复制代码
class Car {
  drive() {
    console.log('Driving a car');
  }
}

class Truck {
  drive() {
    console.log('Driving a truck');
  }
}

// 客户端代码直接依赖具体类
const vehicle1 = new Car();
const vehicle1 = new Truck();

这种写法的问题在于,客户端代码直接依赖于具体类,一旦需要添加新的车辆类型或修改创建逻辑,就需要在所有使用的地方进行修改。

实现开闭原则

工厂方法模式帮助你的代码遵循开闭原则:对扩展开放,对修改关闭。你可以添加新的产品类型而无需修改现有代码。

工厂方法模式实现

让我们通过一个完整的示例来理解工厂方法模式。

第一步:定义产品接口

typescript 复制代码
interface Vehicle {
  drive(): void;
  getInfo(): string;
}

第二步:实现具体产品类

typescript 复制代码
class Car implements Vehicle {
  drive() {
    console.log('Driving a car');
  }
  
  getInfo(): string {
    return 'This is a car with 4 seats';
  }
}

class Truck implements Vehicle {
  drive() {
    console.log('Driving a truck');
  }
  
  getInfo(): string {
    return 'This is a truck for heavy loads';
  }
}

class Motorcycle implements Vehicle {
  drive() {
    console.log('Riding a motorcycle');
  }
  
  getInfo(): string {
    return 'This is a motorcycle with 2 wheels';
  }
}

第三步:创建抽象创建者类

typescript 复制代码
abstract class VehicleFactory {
  // 工厂方法
  public abstract createVehicle(): Vehicle;
  
  // 业务逻辑方法
  public deliverVehicle(): string {
    const vehicle = this.createVehicle();
    vehicle.drive();
    return vehicle.getInfo();
  }
}

第四步:实现具体创建者类

typescript 复制代码
class CarFactory extends VehicleFactory {
  public createVehicle(): Vehicle {
    return new Car();
  }
}

class TruckFactory extends VehicleFactory {
  public createVehicle(): Vehicle {
    return new Truck();
  }
}

class MotorcycleFactory extends VehicleFactory {
  public createVehicle(): Vehicle {
    return new Motorcycle();
  }
}

第五步:客户端使用

typescript 复制代码
function clientCode(factory: VehicleFactory) {
  console.log('Client: Delivery process started...');
  const result = factory.deliverVehicle();
  console.log(result);
}

// 使用不同的工厂创建不同的产品
console.log('App: Launched with CarFactory.');
clientCode(new CarFactory());

console.log('\nApp: Launched with TruckFactory.');
clientCode(new TruckFactory());

console.log('\nApp: Launched with MotorcycleFactory.');
clientCode(new MotorcycleFactory());

高级应用:参数化工厂方法

在某些场景下,你可能希望通过参数来决定创建哪种产品:

typescript 复制代码
class UniversalVehicleFactory extends VehicleFactory {
  constructor(private vehicleType: 'car' | 'truck' | 'motorcycle') {
    super();
  }
  
  public createVehicle(): Vehicle {
    switch (this.vehicleType) {
      case 'car':
        return new Car();
      case 'truck':
        return new Truck();
      case 'motorcycle':
        return new Motorcycle();
      default:
        throw new Error('Unknown vehicle type');
    }
  }
}

// 使用参数化工厂
const carFactory = new UniversalVehicleFactory('car');
clientCode(carFactory);

结合 TypeScript 的高级特性

使用泛型增强类型安全

typescript 复制代码
abstract class GenericVehicleFactory<T extends Vehicle> {
  public abstract createVehicle(): T;
  
  public deliverVehicle(): string {
    const vehicle = this.createVehicle();
    vehicle.drive();
    return vehicle.getInfo();
  }
}

class GenericCarFactory extends GenericVehicleFactory<Car> {
  public createVehicle(): Car {
    return new Car();
  }
}

利用枚举提高代码可读性

typescript 复制代码
enum VehicleType {
  CAR = 'car',
  TRUCK = 'truck',
  MOTORCYCLE = 'motorcycle'
}

class EnumVehicleFactory extends VehicleFactory {
  constructor(private type: VehicleType) {
    super();
  }
  
  public createVehicle(): Vehicle {
    switch (this.type) {
      case VehicleType.CAR:
        return new Car();
      case VehicleType.TRUCK:
        return new Truck();
      case VehicleType.MOTORCYCLE:
        return new Motorcycle();
    }
  }
}

实际应用场景

场景一:UI 组件库

在不同平台(Web、Mobile、Desktop)上创建相同功能的 UI 组件:

typescript 复制代码
interface Button {
  render(): void;
  onClick(callback: () => void): void;
}

class WebButton implements Button {
  render() { console.log('Rendering web button'); }
  onClick(callback: () => void) { /* web 实现 */ }
}

class MobileButton implements Button {
  render() { console.log('Rendering mobile button'); }
  onClick(callback: () => void) { /* mobile 实现 */ }
}

abstract class UIFactory {
  abstract createButton(): Button;
  abstract createModal(): Modal; // 假设有 Modal 接口
}

class WebUIFactory extends UIFactory {
  createButton(): Button { return new WebButton(); }
  createModal(): Modal { return new WebModal(); }
}

场景二:数据库连接工厂

typescript 复制代码
interface DatabaseConnection {
  connect(): void;
  query(sql: string): any[];
}

class MySQLConnection implements DatabaseConnection {
  connect() { console.log('Connecting to MySQL'); }
  query(sql: string) { return []; }
}

class PostgreSQLConnection implements DatabaseConnection {
  connect() { console.log('Connecting to PostgreSQL'); }
  query(sql: string) { return []; }
}

abstract class DatabaseFactory {
  abstract createConnection(): DatabaseConnection;
}

class MySQLFactory extends DatabaseFactory {
  createConnection(): DatabaseConnection {
    return new MySQLConnection();
  }
}

真实案例

TypeORM 的 Driver 工厂 使用工厂方法来根据数据库类型创建不同驱动实例。

typescript 复制代码
export class DriverFactory {
  create(connection: Connection): Driver {
    switch (connection.options.type) {
      case "mysql":
        return new MysqlDriver(connection)
      case "postgres":
        return new PostgresDriver(connection)
      case "sqlite":
        return new SqliteDriver(connection)
      // ...
    }
  }
}
  • 基于数据库类型返回不同的 Driver 子类
  • 统一入口 create()
  • 使用者不关心具体 driver,只依赖 Driver 接口

工厂方法模式的优势与局限

优势

  1. 避免紧耦合:客户端代码只依赖于抽象接口,不依赖于具体类
  2. 单一职责原则:将创建逻辑集中在一个地方,便于维护
  3. 开闭原则:添加新产品类型时无需修改现有代码
  4. 代码可测试性:可以轻松创建模拟对象进行单元测试

局限

  1. 代码复杂度增加:需要引入多个额外的类和接口
  2. 可能过度设计:对于简单场景,直接实例化可能更合适

实践建议

  1. 适时使用:当预计会有多种类似产品,或创建逻辑比较复杂时使用
  2. 结合依赖注入:在大型应用中,结合依赖注入容器使用效果更佳
  3. 文档化工厂意图:明确每个工厂的职责和适用场景
  4. 考虑简单工厂:如果产品类型不多,可以考虑使用简单工厂模式

总结

工厂方法模式是开发中极其重要的设计模式,它通过将对象的创建与使用分离,显著提高了代码的灵活性和可维护性。虽然会引入一定的复杂度,但在面对变化和扩展需求时,这种前期的投入会带来长期的收益。

掌握工厂方法模式,意味着你不仅学会了如何创建对象,更学会了如何以更加优雅和可持续的方式构建软件系统。在实际项目中,工厂方法模式能够帮助你构建出更加健壮和可扩展的应用程序。

相关推荐
桦说编程12 小时前
Guava 迭代器增强类介绍
java·后端·设计模式
李宥小哥17 小时前
创建型设计模式1
stm32·嵌入式硬件·设计模式
李宥小哥18 小时前
结构型设计模式2
网络·数据库·设计模式
guangzan20 小时前
TypeScript 中的策略模式
设计模式
乐悠小码1 天前
Java设计模式精讲---04原型模式
java·设计模式·原型模式
李宥小哥1 天前
行为型设计模式2
windows·设计模式
Juchecar1 天前
Java示例:设计模式是如何在实战中“自然生长”出来
java·设计模式
Juchecar1 天前
超越经典23种设计模式:新模式、反模式与函数式编程
设计模式·云原生·函数式编程