创建型模式

113 阅读5分钟

创建型模式包括单例、工厂方法、抽象工厂、建造者和原型,分别用于全局唯一实例、对象创建解耦、产品族构建、分步生成复杂对象和克隆原型,提升代码复用性和维护性。


1. 单例模式(Singleton)

定义

确保一个类只有一个实例,并提供全局访问点。

结构

  • 私有构造函数(防止外部实例化)
  • 静态成员变量保存唯一实例
  • 静态方法提供全局访问入口

Java 实现

// 枚举实现(线程安全,防止反射攻击)
public enum Singleton {
    INSTANCE;
    public void doSomething() {
        System.out.println("Singleton instance is working.");
    }
}
​
// 静态内部类实现(延迟加载,线程安全)
public class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

适用场景

  • 全局配置管理(如数据库连接池)
  • 日志记录器、工具类等需要唯一实例的场景

优缺点

  • 优点:节省内存、严格控全局访问点。
  • 缺点:可能引入全局状态,测试困难,违反单一职责原则。

2. 工厂方法模式(Factory Method)

定义

定义一个创建对象的接口,但由子类决定实例化哪个类。

结构

  • 抽象工厂接口:声明创建对象的方法
  • 具体工厂类:实现接口,创建具体对象
  • 抽象产品接口:定义产品规范
  • 具体产品类:实现产品接口

Java 实现

// 抽象产品
interface Transport {
    void deliver();
}
​
// 具体产品
class Truck implements Transport {
    @Override
    public void deliver() {
        System.out.println("Delivering by land.");
    }
}
​
class Ship implements Transport {
    @Override
    public void deliver() {
        System.out.println("Delivering by sea.");
    }
}
​
// 抽象工厂
interface Logistics {
    Transport createTransport();
}
​
// 具体工厂
class RoadLogistics implements Logistics {
    @Override
    public Transport createTransport() {
        return new Truck();
    }
}
​
class SeaLogistics implements Logistics {
    @Override
    public Transport createTransport() {
        return new Ship();
    }
}
​
// 客户端调用
public class Client {
    public static void main(String[] args) {
        Logistics logistics = new RoadLogistics();
        Transport transport = logistics.createTransport();
        transport.deliver(); // 输出: Delivering by land.
    }
}

适用场景

  • 跨平台UI组件创建(如不同操作系统下的按钮)
  • 需要解耦对象创建逻辑的场景

优缺点

  • 优点:符合开闭原则,扩展性强。
  • 缺点:每新增一个产品需要新增工厂类,类数量增加。

3. 抽象工厂模式(Abstract Factory)

定义

创建一组相关或依赖对象的族,而无需指定具体类。

结构

  • 抽象工厂接口:定义创建一族产品的方法
  • 具体工厂类:实现接口,创建同一族的不同产品
  • 抽象产品接口:定义产品族中每个产品的规范
  • 具体产品类:实现同一族的不同产品

Java 实现

// 抽象产品族:家具
interface Chair {
    void sitOn();
}
interface Sofa {
    void lieOn();
}
​
// 具体产品:现代风格
class ModernChair implements Chair {
    @Override
    public void sitOn() {
        System.out.println("Sitting on a modern chair.");
    }
}
class ModernSofa implements Sofa {
    @Override
    public void lieOn() {
        System.out.println("Lying on a modern sofa.");
    }
}
​
// 具体产品:复古风格
class VintageChair implements Chair {
    @Override
    public void sitOn() {
        System.out.println("Sitting on a vintage chair.");
    }
}
class VintageSofa implements Sofa {
    @Override
    public void lieOn() {
        System.out.println("Lying on a vintage sofa.");
    }
}
​
// 抽象工厂
interface FurnitureFactory {
    Chair createChair();
    Sofa createSofa();
}
​
// 具体工厂
class ModernFurnitureFactory implements FurnitureFactory {
    @Override
    public Chair createChair() {
        return new ModernChair();
    }
    @Override
    public Sofa createSofa() {
        return new ModernSofa();
    }
}
​
class VintageFurnitureFactory implements FurnitureFactory {
    @Override
    public Chair createChair() {
        return new VintageChair();
    }
    @Override
    public Sofa createSofa() {
        return new VintageSofa();
    }
}
​
// 客户端调用
public class Client {
    public static void main(String[] args) {
        FurnitureFactory factory = new ModernFurnitureFactory();
        Chair chair = factory.createChair();
        Sofa sofa = factory.createSofa();
        chair.sitOn(); // 输出: Sitting on a modern chair.
        sofa.lieOn();  // 输出: Lying on a modern sofa.
    }
}

适用场景

  • 需要创建一组风格统一的对象(如UI主题、跨平台组件)
  • 系统需要独立于产品的创建和组合

优缺点

  • 优点:保证产品族的兼容性,符合开闭原则。
  • 缺点:新增产品族容易,但新增产品类型困难(需修改所有工厂)。

4. 建造者模式(Builder)

定义

分步骤构建复杂对象,分离构造过程与表示。

结构

  • 建造者接口:定义构建步骤
  • 具体建造者:实现接口,构建具体对象
  • 指挥者(Director) :控制构建流程
  • 产品类:最终构建的复杂对象

Java 实现

// 复杂对象:汽车
class Car {
    private String engine;
    private int seats;
    private boolean hasGPS;
​
    public void setEngine(String engine) { this.engine = engine; }
    public void setSeats(int seats) { this.seats = seats; }
    public void setHasGPS(boolean hasGPS) { this.hasGPS = hasGPS; }
}
​
// 抽象建造者
interface CarBuilder {
    void reset();
    void buildEngine();
    void buildSeats();
    void buildGPS();
    Car getResult();
}
​
// 具体建造者:跑车
class SportsCarBuilder implements CarBuilder {
    private Car car;
    public SportsCarBuilder() { this.reset(); }
    @Override
    public void reset() { car = new Car(); }
    @Override
    public void buildEngine() { car.setEngine("V8"); }
    @Override
    public void buildSeats() { car.setSeats(2); }
    @Override
    public void buildGPS() { car.setHasGPS(true); }
    @Override
    public Car getResult() { return car; }
}
​
// 指挥者
class Director {
    public void constructSportsCar(CarBuilder builder) {
        builder.reset();
        builder.buildEngine();
        builder.buildSeats();
        builder.buildGPS();
    }
}
​
// 客户端调用
public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        CarBuilder builder = new SportsCarBuilder();
        director.constructSportsCar(builder);
        Car car = builder.getResult();
    }
}

适用场景

  • 构造复杂对象(如SQL查询语句、XML文档生成)
  • 需要不同配置的对象变体(如汽车的高配/低配)

优缺点

  • 优点:封装构造细节,支持分步构造。
  • 缺点:代码量增加,产品需高度相似。

5. 原型模式(Prototype)

定义

通过复制现有对象(原型)来创建新对象。

结构

  • 原型接口:声明克隆方法(如 Cloneable
  • 具体原型类:实现克隆方法(深拷贝/浅拷贝)

Java 实现

// 原型接口(Java 中 Cloneable 是标记接口)
class Shape implements Cloneable {
    private String type;
    public Shape(String type) { this.type = type; }
    @Override
    public Shape clone() {
        try {
            return (Shape) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
    public String getType() { return type; }
}
​
// 客户端调用
public class Client {
    public static void main(String[] args) {
        Shape circle = new Shape("Circle");
        Shape clonedCircle = circle.clone();
        System.out.println(clonedCircle.getType()); // 输出: Circle
    }
}

适用场景

  • 需要高性能创建相似对象(如游戏中的大量敌人克隆)
  • 避免构造复杂对象的初始化逻辑

优缺点

  • 优点:避免重复初始化,提升性能。
  • 缺点:深拷贝实现复杂,可能破坏封装性(需访问私有字段)。

总结

  1. 单例:全局唯一实例。
  2. 工厂方法:子类决定对象类型。
  3. 抽象工厂:创建一族对象。
  4. 建造者:分步构造复杂对象。
  5. 原型:克隆已有对象。

最佳实践

  • 优先选择静态工厂方法(如 LocalDate.now())代替 new
  • 使用枚举实现单例以避免反射攻击。
  • 建造者模式适合构造参数多且可选的对象(如 StringBuilder)。
  • 原型模式需谨慎处理深拷贝问题(推荐使用序列化或工具库如 Apache Commons)。