一、为什么需要创建型模式?

想象你正在搭积木。每次需要新零件时,要么现场切割木块(直接new对象),要么从标准化模具里取现成的(使用设计模式)。Pascal这种结构化语言虽然不像面向对象语言那样天生支持设计模式,但通过巧妙组织代码,同样能获得类似的好处。

创建型模式就像你的零件工厂,帮你解决:

  • 对象创建过程复杂(比如需要多步初始化)
  • 对象创建需要隔离(避免到处写new)
  • 系统需要灵活切换对象类型

举个真实场景:我们电商系统要处理三种支付方式(支付宝/微信/银联),如果每次都在业务代码里写if...else来创建支付处理器,不仅难看,以后新增支付方式还得改几十个地方。

二、简单工厂模式实战

(示例技术栈:Free Pascal/Lazarus)

// 支付处理器基类
type
  TPaymentHandler = class
  public
    procedure ProcessPayment(amount: Double); virtual; abstract;
  end;

// 具体支付实现
type
  TAlipayHandler = class(TPaymentHandler)
  public
    procedure ProcessPayment(amount: Double); override;
    begin
      WriteLn('支付宝处理支付: ', amount:0:2);
    end;
  end;

// 支付工厂
type
  TPaymentFactory = class
  public
    class function CreateHandler(paymentType: string): TPaymentHandler;
  end;

class function TPaymentFactory.CreateHandler(paymentType: string): TPaymentHandler;
begin
  if paymentType = 'alipay' then
    Result := TAlipayHandler.Create
  else if paymentType = 'wechat' then
    Result := TWechatHandler.Create
  else
    raise Exception.Create('不支持的支付类型');
end;

// 使用示例
var
  handler: TPaymentHandler;
begin
  handler := TPaymentFactory.CreateHandler('alipay');
  try
    handler.ProcessPayment(99.99);
  finally
    handler.Free;
  end;
end.

这个方案把创建逻辑集中到了工厂类,业务代码只需要知道"我需要一个支付处理器",不用关心具体类型。但缺点也很明显——每新增支付方式都要修改工厂类,违反开闭原则。

三、工厂方法模式进阶

为了解决简单工厂的问题,我们升级成工厂方法模式:

// 抽象工厂
type
  IPaymentHandlerFactory = interface
    function CreateHandler: TPaymentHandler;
  end;

// 支付宝工厂
type
  TAlipayFactory = class(TInterfacedObject, IPaymentHandlerFactory)
    function CreateHandler: TPaymentHandler;
  end;

function TAlipayFactory.CreateHandler: TPaymentHandler;
begin
  Result := TAlipayHandler.Create;
end;

// 在配置阶段注册工厂
var
  factories: TDictionary<string, IPaymentHandlerFactory>;
begin
  factories := TDictionary<string, IPaymentHandlerFactory>.Create;
  factories.Add('alipay', TAlipayFactory.Create);
  // 可以继续添加其他支付工厂...
  
  // 使用时
  handler := factories['alipay'].CreateHandler;
  handler.ProcessPayment(88.88);
end.

这个版本的进步在于:

  1. 新增支付类型只需新建工厂类,不用改原有代码
  2. 可以通过配置文件动态决定使用哪个工厂
  3. 符合"对扩展开放,对修改关闭"的原则

四、建造者模式处理复杂对象

当对象需要多步构造时,比如我们的订单系统要生成包含商品、优惠、物流的复杂订单:

type
  // 要构建的复杂对象
  TOrder = class
  public
    Items: TArray<string>;
    Discount: Double;
    ShippingMethod: string;
  end;

  // 建造者接口
  IOrderBuilder = interface
    procedure AddItems(items: TArray<string>);
    procedure ApplyDiscount(discount: Double);
    procedure SetShipping(method: string);
    function GetResult: TOrder;
  end;

  // 具体建造者
  TStandardOrderBuilder = class(TInterfacedObject, IOrderBuilder)
  private
    FOrder: TOrder;
  public
    constructor Create;
    procedure AddItems(items: TArray<string>);
    begin
      FOrder.Items := items;
    end;
    
    function GetResult: TOrder;
    begin
      Result := FOrder;
      FOrder := nil; // 转移所有权
    end;
    // 其他方法实现...
  end;

// 使用示例
var
  builder: IOrderBuilder;
  order: TOrder;
begin
  builder := TStandardOrderBuilder.Create;
  builder.AddItems(['商品A', '商品B']);
  builder.ApplyDiscount(0.9);
  builder.SetShipping('顺丰');
  order := builder.GetResult;
  // 使用order对象...
end;

建造者模式特别适合:

  • 需要分步构造的对象
  • 相同构造过程需要创建不同表现的对象
  • 需要隔离复杂对象的创建细节

五、单例模式的正确姿势

全局配置管理器通常只需要一个实例:

type
  TConfigManager = class
  private
    class var FInstance: TConfigManager;
    constructor CreatePrivate; // 私有化构造
  public
    class function GetInstance: TConfigManager;
    class procedure ReleaseInstance;
    // 其他业务方法...
  end;

class function TConfigManager.GetInstance: TConfigManager;
begin
  if not Assigned(FInstance) then
    FInstance := CreatePrivate;
  Result := FInstance;
end;

// 线程安全改进版
class function TConfigManager.GetInstance: TConfigManager;
var
  temp: TConfigManager;
begin
  if not Assigned(FInstance) then
  begin
    temp := CreatePrivate;
    if TInterlocked.ComparePointer(Pointer(FInstance), nil, Pointer(temp)) <> nil then
      temp.Free;
  end;
  Result := FInstance;
end;

注意事项:

  1. 要考虑线程安全(如上面改进版所示)
  2. 单例生命周期通常与程序一致
  3. 过度使用单例会变成"高级全局变量"

六、原型模式优化性能

当创建对象成本很高时(比如要读取大文件初始化),我们可以克隆现有对象:

type
  IPrototype = interface
    function Clone: IPrototype;
  end;

  TExpensiveObject = class(TInterfacedObject, IPrototype)
  private
    FData: TArray<Byte>;
  public
    constructor CreateFromFile(const filename: string);
    function Clone: IPrototype;
  end;

function TExpensiveObject.Clone: IPrototype;
var
  copy: TExpensiveObject;
begin
  copy := TExpensiveObject.Create;
  SetLength(copy.FData, Length(FData));
  Move(FData[0], copy.FData[0], Length(FData));
  Result := copy;
end;

适用场景:

  • 对象创建需要大量计算或IO操作
  • 系统需要频繁创建相似对象
  • 需要避免使用类的构造器

七、模式选择指南

最后给个快速选型参考表:

问题场景 推荐模式 理由
需要统一创建入口 简单工厂 集中管理创建逻辑
需要灵活扩展产品类型 工厂方法 符合开闭原则
构造过程复杂 建造者 分离构造步骤
全局唯一访问点 单例 控制实例数量
创建成本高昂的对象 原型 通过克隆避免重复初始化

实际项目中常常组合使用这些模式。比如用工厂方法创建建造者,再由建造者生成最终对象。

记住:设计模式不是银弹,用对场景才是关键。下次当你发现代码里new关键字满天飞,或者构造逻辑重复N遍时,就该考虑引入合适的创建型模式了。