2设计模式

创建型模式

对象创建的抽象

Abstract FactoryBuilderFactory MethodPrototypeSingleton

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第2章:创建型模式(Creational Patterns)

一、导读

1.1 本章学习目标

第2章介绍 5 个创建型模式。创建型模式封装了对象创建的过程,将对象的创建与使用分离,使系统设计更加灵活。

本章的核心学习目标包括:

  • 掌握 Factory Method:定义创建对象的接口,让子类决定实例化哪个类
  • 理解 Abstract Factory:创建一系列相关对象
  • 学会 Builder:分步骤构建复杂对象
  • 掌握 Prototype:通过复制现有对象创建新对象
  • 理解 Singleton:确保一个类只有一个实例

1.2 为什么本章如此重要

创建型模式是所有设计模式中最基础的一类。它们解决的核心问题是:如何灵活地创建对象。在很多系统中,对象的创建逻辑是复杂且多变的——如果将创建逻辑硬编码在使用处,系统就会变得僵化。创建型模式通过将创建逻辑封装起来,使系统更加灵活和可扩展。

1.3 核心问题引导

Factory Method 与 Abstract Factory 有什么区别?

什么时候应该使用 Builder 而不是构造函数?

Prototype 模式在什么场景下有用?

Singleton 模式有什么争议?为什么很多人反对使用它?

创建型模式如何使系统更加灵活?


二、核心概念详解

2.1 Factory Method(工厂方法)

意图:定义一个创建对象的接口,但让子类决定实例化哪个类。工厂方法将实例化推迟到子类。

适用场景:

  • 一个类无法知道它必须创建的对象的具体类
  • 一个类希望由子类来指定创建的对象
  • 一个类将创建对象的职责委托给多个辅助子类中的某一个
java
// 工厂方法模式
abstract class Dialog {
  // 工厂方法
  abstract Button createButton();
  
  void render() {
    Button button = createButton();
    button.render();
  }
}

class WindowsDialog extends Dialog {
  Button createButton() {
    return new WindowsButton();
  }
}

class WebDialog extends Dialog {
  Button createButton() {
    return new HTMLButton();
  }
}

interface Button {
  void render();
  void onClick();
}

class WindowsButton implements Button {
  public void render() { System.out.println("Rendering Windows button"); }
  public void onClick() { System.out.println("Windows button clicked"); }
}

class HTMLButton implements Button {
  public void render() { System.out.println("Rendering HTML button"); }
  public void onClick() { System.out.println("HTML button clicked"); }
}

// 使用
Dialog dialog = new WindowsDialog(); // 或 new WebDialog()
dialog.render(); // 自动创建对应平台的按钮

2.2 Abstract Factory(抽象工厂)

意图:提供一个创建一系列相关对象的接口,而无需指定它们的具体类。

与 Factory Method 的区别:Factory Method 创建单个产品,Abstract Factory 创建一系列相关产品(产品族)。

java
// 抽象工厂模式
interface GUIFactory {
  Button createButton();
  Checkbox createCheckbox();
}

class WindowsFactory implements GUIFactory {
  public Button createButton() { return new WindowsButton(); }
  public Checkbox createCheckbox() { return new WindowsCheckbox(); }
}

class MacFactory implements GUIFactory {
  public Button createButton() { return new MacButton(); }
  public Checkbox createCheckbox() { return new MacCheckbox(); }
}

class Application {
  private Button button;
  private Checkbox checkbox;
  
  Application(GUIFactory factory) {
    button = factory.createButton();
    checkbox = factory.createCheckbox();
  }
  
  void render() {
    button.render();
    checkbox.render();
  }
}

// 使用:确保同一产品族的组件一起使用
Application app = new Application(new WindowsFactory());
app.render(); // 所有组件都是 Windows 风格

2.3 Builder(建造者)

意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

适用场景:

  • 创建复杂对象的算法应该独立于对象的组成部分
  • 构造过程需要允许被构造的对象有不同的表示
java
// Builder 模式
class House {
  private String foundation;
  private String walls;
  private String roof;
  private boolean hasGarage;
  private boolean hasSwimmingPool;
  private boolean hasGarden;
  
  // 私有构造函数
  private House(Builder builder) {
    this.foundation = builder.foundation;
    this.walls = builder.walls;
    this.roof = builder.roof;
    this.hasGarage = builder.hasGarage;
    this.hasSwimmingPool = builder.hasSwimmingPool;
    this.hasGarden = builder.hasGarden;
  }
  
  static class Builder {
    private String foundation;
    private String walls;
    private String roof;
    private boolean hasGarage;
    private boolean hasSwimmingPool;
    private boolean hasGarden;
    
    Builder(String foundation, String walls, String roof) {
      this.foundation = foundation;
      this.walls = walls;
      this.roof = roof;
    }
    
    Builder withGarage() { this.hasGarage = true; return this; }
    Builder withSwimmingPool() { this.hasSwimmingPool = true; return this; }
    Builder withGarden() { this.hasGarden = true; return this; }
    
    House build() {
      return new House(this);
    }
  }
}

// 使用
House simpleHouse = new House.Builder("concrete", "brick", "tile")
  .build();

House luxuryHouse = new House.Builder("concrete", "marble", "slate")
  .withGarage()
  .withSwimmingPool()
  .withGarden()
  .build();

2.4 Prototype(原型)

意图:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

适用场景:

  • 当要实例化的类是在运行时刻指定时
  • 为了避免创建与产品类层次平行的工厂类层次时
  • 当一个类的实例只能有几个不同状态组合中的一种时
java
// Prototype 模式
abstract class Shape implements Cloneable {
  protected String color;
  
  abstract Shape clone();
  
  abstract String getInfo();
}

class Circle extends Shape {
  private double radius;
  
  Circle(String color, double radius) {
    this.color = color;
    this.radius = radius;
  }
  
  Shape clone() {
    return new Circle(this.color, this.radius);
  }
  
  String getInfo() {
    return "Circle: color=" + color + ", radius=" + radius;
  }
}

class Rectangle extends Shape {
  private double width, height;
  
  Rectangle(String color, double width, double height) {
    this.color = color;
    this.width = width;
    this.height = height;
  }
  
  Shape clone() {
    return new Rectangle(this.color, this.width, this.height);
  }
  
  String getInfo() {
    return "Rectangle: color=" + color + ", width=" + width + ", height=" + height;
  }
}

// 使用原型注册表
class ShapeRegistry {
  private Map<String, Shape> prototypes = new HashMap<>();
  
  void register(String name, Shape shape) {
    prototypes.put(name, shape);
  }
  
  Shape create(String name) {
    return prototypes.get(name).clone();
  }
}

// 使用
ShapeRegistry registry = new ShapeRegistry();
registry.register("red-circle", new Circle("red", 5));
registry.register("blue-rect", new Rectangle("blue", 10, 20));

Shape circle1 = registry.create("red-circle");
Shape circle2 = registry.create("red-circle"); // 复制原型

2.5 Singleton(单例)

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

争议:Singleton 模式被广泛使用但也备受争议。它引入了全局状态,使得测试困难,隐藏了依赖关系。在很多场景下,依赖注入是更好的选择。

java
// 经典的单例实现(线程安全)
public class Database {
  private static volatile Database instance;
  private Connection connection;
  
  private Database() {
    // 私有构造函数,防止外部实例化
    this.connection = connectToDatabase();
  }
  
  public static Database getInstance() {
    if (instance == null) {
      synchronized (Database.class) {
        if (instance == null) {
          instance = new Database();
        }
      }
    }
    return instance;
  }
  
  private Connection connectToDatabase() {
    // 连接数据库
    return null;
  }
}

// 更现代的方式:使用枚举
public enum Database {
  INSTANCE;
  
  private Connection connection;
  
  Database() {
    this.connection = connectToDatabase();
  }
  
  public Connection getConnection() {
    return connection;
  }
  
  private Connection connectToDatabase() {
    return null;
  }
}

三、实战案例

3.1 案例:日志系统的创建

java
// 使用工厂方法创建不同目标的日志器
abstract class LoggerFactory {
  abstract Logger createLogger();
  
  void log(String message) {
    Logger logger = createLogger();
    logger.write(message);
  }
}

class ConsoleLoggerFactory extends LoggerFactory {
  Logger createLogger() {
    return new ConsoleLogger();
  }
}

class FileLoggerFactory extends LoggerFactory {
  private String filePath;
  
  FileLoggerFactory(String filePath) {
    this.filePath = filePath;
  }
  
  Logger createLogger() {
    return new FileLogger(filePath);
  }
}

interface Logger {
  void write(String message);
}

class ConsoleLogger implements Logger {
  public void write(String message) {
    System.out.println("[LOG] " + message);
  }
}

class FileLogger implements Logger {
  private String filePath;
  
  FileLogger(String filePath) {
    this.filePath = filePath;
  }
  
  public void write(String message) {
    // 写入文件
  }
}

// 使用
LoggerFactory factory = new ConsoleLoggerFactory();
factory.log("Application started");

四、本章小结

本章介绍了 5 个创建型模式:

Factory Method:定义创建接口,让子类决定实例化哪个类

Abstract Factory:创建一系列相关产品

Builder:分步骤构建复杂对象

Prototype:通过复制原型创建新对象

Singleton:确保一个类只有一个实例

创建型模式的核心思想是:将对象的创建与使用分离,使系统更加灵活。


五、思考与练习

思考题

Factory Method 和 Abstract Factory 如何选择?

Builder 模式与直接设置属性有什么区别?

Singleton 有什么问题?有哪些替代方案?

Prototype 模式在 Java 中如何实现深复制?

编程练习

使用 Factory Method 实现一个跨平台的 UI 组件库。

使用 Builder 模式实现一个复杂的 HTTP 请求构建器。

使用 Prototype 模式实现一个游戏角色的克隆系统。


2/6创建型模
0%