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

在软件开发过程中,对象的创建可能是最频繁的操作。假设你要开汉堡店,选择原料供应商(如何造汉堡)、定制套餐组合(如何组织对象)、应对突发需求(如何适应变化)都需要策略。这时设计模式就像经营手册,下面我们聚焦三个最常见的创建模式。


二、工厂方法模式:单品生产线

2.1 模式定义

工厂方法定义一个接口用于创建对象,但让子类决定实例化哪个类。如同特许经营店,总部制定标准,分店自行选择配料。

// 技术栈:Java 17
interface Burger {
    void addSauce();
}

class BeefBurger implements Burger {
    @Override
    public void addSauce() {
        System.out.println("添加黑椒酱汁");
    }
}

abstract class BurgerShop {
    // 工厂方法声明
    public abstract Burger createBurger();
    
    public void orderBurger() {
        Burger burger = createBurger();
        burger.addSauce();
    }
}

class BeefBurgerShop extends BurgerShop {
    @Override
    public Burger createBurger() {
        return new BeefBurger();
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        BurgerShop shop = new BeefBurgerShop();
        shop.orderBurger();  // 输出:添加黑椒酱汁
    }
}

2.2 应用场景

  • 快递系统需要区分不同运输方式
  • 游戏装备需要根据角色职业生成不同武器
  • 日志系统需要支持多种日志记录方式

三、抽象工厂模式:全套供应链

3.1 双重抽象设计

当需要生产整套相关产品时,抽象工厂就像连锁餐厅的中央厨房:

// 完整套餐接口
interface MealCombo {
    Burger createBurger();
    Drink createDrink();
}

// 美式风味工厂
class AmericanCombo implements MealCombo {
    @Override
    public Burger createBurger() {
        return new BeefBurger();
    }
    
    @Override
    public Drink createDrink() {
        return new Cola();
    }
}

// 中式风味工厂
class ChineseCombo implements MealCombo {
    @Override
    public Burger createBurger() {
        return new PorkBurger();
    }
    
    @Override
    public Drink createDrink() {
        return new SoyMilk();
    }
}

// 使用示例
public class Kitchen {
    public void prepareMeal(MealCombo factory) {
        Burger burger = factory.createBurger();
        Drink drink = factory.createDrink();
        // 打包操作...
    }
}

3.2 核心技术特征

  • 产品之间强关联性(如操作系统主题组件)
  • 需要约束产品兼容性(如汽车不同型号的配件)
  • 整体替换产品族更方便

四、建造者模式:分步装配大师

4.1 灵活构建流程

面对复杂对象,建造者模式像乐高说明书:

class CustomBurger {
    private List<String> layers = new ArrayList<>();
    
    public void addLayer(String ingredient) {
        layers.add(ingredient);
    }
    
    public void showBurger() {
        System.out.println("当前汉堡结构:" + String.join("+", layers));
    }
}

// 建造者接口
interface BurgerBuilder {
    void addBread();
    void addPatty();
    void addVegetables();
    CustomBurger getResult();
}

class DeluxeBuilder implements BurgerBuilder {
    private CustomBurger burger = new CustomBurger();
    
    @Override
    public void addBread() {
        burger.addLayer("全麦面包");
    }
    
    @Override
    public void addPatty() {
        burger.addLayer("双层牛肉饼");
    }
    
    @Override
    public void addVegetables() {
        burger.addLayer("生菜+番茄");
    }
    
    @Override
    public CustomBurger getResult() {
        return burger;
    }
}

// 导演类控制流程
class Chef {
    public CustomBurger construct(BurgerBuilder builder) {
        builder.addBread();
        builder.addPatty();
        builder.addVegetables();
        builder.addBread();
        return builder.getResult();
    }
}

4.2 模式优势验证

  • 允许通过不同Builder实现改变内部结构
  • 避免构造函数参数爆炸(特别是可选参数多的场景)
  • 支持渐进式对象构建

五、模式对比与选型指南

5.1 适用场景对照表

模式名称 最佳使用场景 典型案例
工厂方法 单个产品的多态创建 数据库连接器选择
抽象工厂 相关产品族的创建 跨平台UI组件套件
建造者 复杂对象的分步构造 HTTP请求配置器

5.2 技术选型注意事项

  • 避免过度设计:简单对象直接使用new关键字
  • 关注扩展方向:垂直扩展选工厂,水平组合用建造者
  • 考虑组合使用:抽象工厂中可以使用工厂方法创建单个产品

六、生产环境中的实战经验

6.1 Spring框架中的典型应用

  • @Bean注解本质是工厂方法
  • BeanFactory与ApplicationContext的关系体现抽象工厂层级
  • RestTemplateBuilder是建造者模式的优秀实践

6.2 性能优化要点

  • 工厂类可以配合缓存机制提升性能
  • 建造者模式较适合创建重量级对象
  • 抽象工厂要注意避免创建不必要的子类

七、总结:模式之外的设计哲学

  • 隔离变化:将可能变化的创建逻辑与业务逻辑解耦
  • 提升内聚:每个类保持单一职责
  • 开放封闭:通过新增实现类扩展功能,而不是修改原有代码