设计模式-创建型模式

创建型模式组成

创建型设计模式关注的是对象的创建过程,旨在将对象的创建与使用分离,从而提高程序的灵活性和可复用性。以下是几种常见的创建型设计模式:

1. 单例模式(Singleton)

  • 目的:确保一个类只有一个实例,并提供一个全局访问点。
  • 应用场景:数据库连接池、配置设置等需要唯一实例的场景。

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

  • 目的:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
  • 应用场景:当一个类无法预料要创建哪种类的对象或希望由其子类来指定创建何种对象时。

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

  • 目的:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
  • 应用场景:GUI工具包中,为不同的操作系统提供统一的界面元素创建机制。

4. 建造者模式(Builder)

  • 目的:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
  • 应用场景:当对象的构造需要很多步骤,但不一定都需要或者不同情况下需要不同的组合时。

5. 原型模式(Prototype)

  • 目的:通过给出一个原型实例来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。
  • 应用场景:当创建新对象的代价较大时,可以通过复制已有对象来减少开销;或者在创建对象时需要避免构造函数的复杂逻辑时。

每种创建型模式都有其特定的应用场景和优势,选择合适的模式取决于具体的需求和上下文环境。理解这些模式可以帮助开发者编写更加灵活、易于维护的代码。此外,合理地应用设计模式能够提高代码的可读性和可扩展性,同时也促进了代码的重用。

工厂模式

  • 工厂方法模式(Factory Method Pattern)
    • 定义一个用于创建对象的接口,但由子类决定实例化哪一个类。
    • 提供了一种创建对象的灵活性,允许类将实例化推迟到子类。
  • 抽象工厂模式(Abstract Factory Pattern)
    • 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
    • 当有一组对象需要一起使用时特别有用,例如不同风格的UI组件集。

工厂方法模式(Factory Method Pattern)和抽象工厂模式(Abstract Factory Pattern)都是创建型设计模式,用于将对象的创建与使用分离,从而提高代码的灵活性和可维护性。然而,它们的应用场景和结构有所不同。

工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪一个类。这种模式让一个类的实例化延迟到其子类。它提供了一种在不修改现有代码的情况下引入新类型的机制,符合开闭原则(对扩展开放,对修改关闭)。

关键点:
  • 定义了一个创建对象的接口。
  • 子类负责实现具体的创建逻辑。
  • 适用于需要根据特定条件创建不同类型的对象的情况。
示例:

假设你有一个Document接口和两个具体实现:PDFDocumentTextDocument。你可以定义一个DocumentCreator类,其中包含一个工厂方法createDocument(),该方法返回Document类型的对象。然后,你可以创建两个子类PDFCreatorTextCreator,分别重写createDocument()以返回相应的文档类型。

抽象工厂模式

抽象工厂模式提供了一组相关或相互依赖的对象的创建接口,而无需指定它们具体的类。这个模式通常用来创建一系列相关的对象,这些对象属于同一个家族,但是每个家族都有不同的变体。

关键点:
  • 提供了一系列产品族的创建接口。
  • 可以创建多个相关的产品对象,这些产品共同构成了一个产品族。
  • 适用于有一系列相关产品对象,并且需要保持一致性的场景。
示例:

继续上面的例子,现在我们不仅有Document,还有Printer。对于每个Document类型(如PDFDocumentTextDocument),我们也有对应的Printer类型(如PDFPrinterTextPrinter)。我们可以定义一个DocumentFactory接口,它有两个方法:createDocument()createPrinter()。然后为每个产品族创建一个具体的工厂类,例如PDFFactoryTextFactory,它们实现了DocumentFactory接口并提供相应的产品组合。

比较

  • 目的:工厂方法模式主要关注于单一产品的创建;而抽象工厂模式侧重于一组相关产品的创建。
  • 复杂度:工厂方法模式相对简单,只需要考虑如何创建一种类型的对象;抽象工厂模式则更复杂,因为它涉及到多种类型的对象之间的关系。
  • 适用性:如果你只需要创建一种类型的对象,那么工厂方法模式就足够了;但如果你需要创建一系列相关的对象,那么应该选择抽象工厂模式。

这两种模式都可以帮助开发者解耦对象的创建过程和使用过程,从而使代码更加灵活、易于维护和扩展。

建造者模式(Builder Pattern)

建造者模式是一种创建型设计模式,它允许逐步构建复杂的对象。建造者模式通常用于以下场景:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;或者当构造过程必须允许被构造的对象有不同的表示时。

下面是一个简单的Java示例,展示了如何使用建造者模式来构建一个复杂的对象——在这里我们以构建一辆Car为例:

// 产品类
class Car {
    private String make;
    private String model;
    private int year;
    private String engine;
    private String transmission;

    // 私有构造函数,防止直接实例化
    private Car(Builder builder) {
        this.make = builder.make;
        this.model = builder.model;
        this.year = builder.year;
        this.engine = builder.engine;
        this.transmission = builder.transmission;
    }

    // 静态内部类 Builder
    public static class Builder {
        private String make;
        private String model;
        private int year;
        private String engine;
        private String transmission;

        // 必填项
        public Builder(String make, String model) {
            this.make = make;
            this.model = model;
        }

        // 可选项 - 设置年份
        public Builder setYear(int year) {
            this.year = year;
            return this; // 返回当前Builder对象,实现链式调用
        }

        // 可选项 - 设置引擎
        public Builder setEngine(String engine) {
            this.engine = engine;
            return this;
        }

        // 可选项 - 设置变速器类型
        public Builder setTransmission(String transmission) {
            this.transmission = transmission;
            return this;
        }

        // 构建最终的Car对象
        public Car build() {
            return new Car(this);
        }
    }

    @Override
    public String toString() {
        return "Car{" +
                "make='" + make + '\'' +
                ", model='" + model + '\'' +
                ", year=" + year +
                ", engine='" + engine + '\'' +
                ", transmission='" + transmission + '\'' +
                '}';
    }
}

// 测试代码
public class TestBuilderPattern {
    public static void main(String[] args) {
        Car car = new Car.Builder("Toyota", "Corolla")
                .setYear(2023)
                .setEngine("1.8L")
                .setTransmission("CVT")
                .build();
        System.out.println(car.toString());
    }
}

在这个例子中,Car 类有一个私有的构造函数,这意味着不能直接通过 new 关键字来创建它的实例。相反,我们提供了一个静态内部类 Builder 来帮助构建 Car 对象。Builder 类包含了所有必要的参数和可选参数,并提供了相应的设置方法。每个设置方法都返回 this 引用,使得可以进行链式调用。最后,通过 build() 方法来创建 Car 实例。这样做的好处是,不仅可以让代码更加清晰,而且还可以确保某些属性在创建对象之前已经被正确设置了。

单例模式(Singleton Pattern)

    • 确保一个类只有一个实例,并提供一个全局访问点。
    • 适用于需要控制资源访问的情况,如数据库连接池。
public class Singleton {
    // 使用 volatile 关键字确保当 uniqueInstance 变量被初始化成 Singleton 实例时,多个线程能够正确处理 uniqueInstance 变量
    private static volatile Singleton uniqueInstance;

    // 私有构造函数,防止外界直接创建 Singleton 的实例
    private Singleton() {}

    // 静态方法,用于获取唯一实例
    public static Singleton getInstance() {
        if (uniqueInstance == null) { // 第一次检查
            synchronized (Singleton.class) {
                if (uniqueInstance == null) { // 第二次检查
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

原型模式(Prototype Pattern)

    • 通过复制现有实例来创建新对象,而不是通过常规构造函数。
    • 对象创建成本较高时,可以通过克隆已有对象来提升性能。
// 定义一个抽象类或接口作为原型
abstract class Prototype implements Cloneable {
    protected String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 克隆当前对象
    public abstract Prototype clone();
}

// 具体的原型类
class ConcretePrototype extends Prototype {

    @Override
    public Prototype clone() {
        try {
            // 调用父类的克隆方法
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

// 测试代码
public class Test {
    public static void main(String[] args) {
        // 创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setName("Prototype1");

        // 通过克隆创建新对象
        ConcretePrototype copy = (ConcretePrototype) prototype.clone();
        System.out.println("Original Name: " + prototype.getName());
        System.out.println("Cloned Name: " + copy.getName());
    }
}

各种工厂模式

日常工作中我们都听说过抽象工厂模式、工厂方法模式、简单工厂模式、静态工厂模式。他们名称类型,以至于傻傻分不清楚。其实他们都属于创建型设计模式,用于对象的创建,但它们各自有不同的应用场景和实现方式。下面我将分别介绍这四种模式。

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

  • 描述:提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
  • 核心思想:通过定义一个抽象层来创建一系列产品,而不是单一的产品。客户端代码使用的是由抽象工厂提供的接口,而不直接依赖于具体的产品类。
  • 优点:易于交换“系列产品”,因为具体工厂类在运行时被实例化;为大规模的产品设计提供了开放式的兼容性。

// 抽象产品A
interface ProductA {}
// 具体产品A1
class ConcreteProductA1 implements ProductA {}
// 具体产品A2
class ConcreteProductA2 implements ProductA {}

// 抽象产品B
interface ProductB {}
// 具体产品B1
class ConcreteProductB1 implements ProductB {}
// 具体产品B2
class ConcreteProductB2 implements ProductB {}

// 抽象工厂
interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    public ProductA createProductA() { return new ConcreteProductA1(); }
    public ProductB createProductB() { return new ConcreteProductB1(); }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    public ProductA createProductA() { return new ConcreteProductA2(); }
    public ProductB createProductB() { return new ConcreteProductB2(); }
}

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

  • 描述:定义一个用于创建对象的接口,但让子类决定将哪一个类实例化。工厂方法使一个类的实例化延迟到其子类。
  • 核心思想:父类定义了一个工厂方法,该方法通常返回一个产品类型。子类重写此方法以返回特定的具体产品。
  • 优点:引入了多态性,允许动态地改变负责创建实例的类,使得系统更加灵活。
// 产品接口
interface Product {
    void use();
}

// 具体产品
class ConcreteProduct implements Product {
    public void use() { /* 使用产品 */ }
}

// 抽象创建者
abstract class Creator {
    // 工厂方法
    abstract Product factoryMethod();
}

// 具体创建者
class ConcreteCreator extends Creator {
    public Product factoryMethod() {
        return new ConcreteProduct();
    }
}

3. 简单工厂模式(Simple Factory)

  • 描述:并不是GoF设计模式之一,但它是一个广泛使用的概念。简单工厂模式是由一个工厂类根据传入的参数决定创建出哪一种产品类的实例。
  • 核心思想:集中化对象的创建逻辑到一个工厂类中,通过传递不同的参数给工厂类的方法来创建不同的对象。
  • 优点:简化了客户端代码,客户端不需要知道具体的类名,只需要知道要创建对象的参数即可。
// 产品接口
interface Product {
    void use();
}

// 具体产品1
class ConcreteProduct1 implements Product {
    public void use() { /* 使用产品 */ }
}

// 具体产品2
class ConcreteProduct2 implements Product {
    public void use() { /* 使用产品 */ }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("ConcreteProduct1".equals(type)) {
            return new ConcreteProduct1();
        } else if ("ConcreteProduct2".equals(type)) {
            return new ConcreteProduct2();
        }
        return null;
    }
}

4. 静态工厂模式(Static Factory)

  • 描述:与简单工厂类似,但工厂方法是静态的。这意味着你不需要创建工厂实例就可以调用工厂方法。
  • 核心思想:通过静态方法提供了一种创建实例的方式,这些方法通常具有特定的名称,表明了它们所创建的对象类型。
  • 优点:可以直接通过类名调用方法来获取实例,不需要实例化工厂类,简化了对象创建过程。
// 产品接口
interface Product {
    void use();
}

// 具体产品
class ConcreteProduct implements Product {
    public void use() { /* 使用产品 */ }
}

// 静态工厂类
class StaticFactory {
    public static Product createProduct() {
        return new ConcreteProduct();
    }
}

每种工厂模式都有其适用场景,选择哪种模式取决于具体的需求和上下文环境。例如,如果你需要创建一系列相关的对象,那么抽象工厂模式可能是最合适的;如果只是想简化对象的创建过程,并且创建逻辑不复杂,可以考虑使用简单工厂或静态工厂模式。工厂方法模式则非常适合那些需要灵活性和扩展性的场合。

你可能感兴趣的:(设计模式)