【建造者模式】结合框架学习设计模式

68 阅读5分钟

建造者模式 Builder Pattern

  • 属于创建型模式
  • 是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
  • 关键点:用户只需要指定需要建造的类型就可以获得对象,建造过程及细节不需要了解

在建造者模式中,主要有以下几个角色:

  1. Builder(抽象建造者) :为创建一个产品对象的各个部件指定抽象接口。在该接口中通常声明两类方法,一类是用于创建复杂对象的各个部件的方法,如buildPartX();另一类是用于返回复杂对象的方法,如getResult()。Builder 既可以是抽象类,也可以是接口。
  2. ConcreteBuilder(具体建造者) :实现了 Builder 接口,具体构造和装配产品的各个部件,定义并明确它所创建的复杂对象,还可以提供一个方法返回创建好的复杂产品对象。
  3. Director(指挥者或导演类) :负责安排复杂对象的建造次序,与抽象建造者之间存在关联关系,可以在其构造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互。
  4. Product(产品) :是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。

业务

类图

classDiagram
    class Car {
        -brand: String
        -model: String
        -color: String
        -engineType: String
        +getBrand(): String
        +getModel(): String
        +getColor(): String
        +getEngineType(): String
    }
    class CarBuilder {
        <<abstract>>
        -car: Car
        +setBrand(String): CarBuilder
        +setModel(String): CarBuilder
        +setColor(String): CarBuilder
        +setEngineType(String): CarBuilder
        +build(): Car
    }
    class ConcreteCarBuilder {
        -car: Car
        +setBrand(String): CarBuilder
        +setModel(String): CarBuilder
        +setColor(String): CarBuilder
        +setEngineType(String): CarBuilder
        +build(): Car
    }
    class CarDirector {
        +createCar(String, String, String, String): Car
    }
    Car <-- CarBuilder
    CarBuilder <|-- ConcreteCarBuilder
    CarDirector --o ConcreteCarBuilder

代码

假设我们正在开发一个汽车制造系统,汽车有品牌、型号、颜色、发动机类型等多个属性。

  1. 定义汽车类(Product):
public class Car {
    private String brand;
    private String model;
    private String color;
    private String engineType;

    // 省略 getters 和 setters
}
  1. 定义抽象建造者(Builder):
public abstract class CarBuilder {
    protected Car car = new Car();

    public abstract CarBuilder setBrand(String brand);
    public abstract CarBuilder setModel(String model);
    public abstract CarBuilder setColor(String color);
    public abstract CarBuilder setEngineType(String engineType);

    public Car build() {
        return car;
    }
}
  1. 具体建造者(ConcreteBuilder):
public class ConcreteCarBuilder extends CarBuilder {
    @Override
    public CarBuilder setBrand(String brand) {
        car.setBrand(brand);
        return this;
    }

    @Override
    public CarBuilder setModel(String model) {
        car.setModel(model);
        return this;
    }

    @Override
    public CarBuilder setColor(String color) {
        car.setColor(color);
        return this;
    }

    @Override
    public CarBuilder setEngineType(String engineType) {
        car.setEngineType(engineType);
        return this;
    }
}
  1. 指挥者(Director):
public class CarDirector {
    public static Car createCar(String brand, String model, String color, String engineType) {
        return new ConcreteCarBuilder()
               .setBrand(brand)
               .setModel(model)
               .setColor(color)
               .setEngineType(engineType)
               .build();
    }
}

使用时:

public class Main {
    public static void main(String[] args) {
        Car car = CarDirector.createCar("Tesla", "Model S", "Red", "Electric");
        System.out.println(car.getBrand() + " " + car.getModel() + " " + car.getColor() + " " + car.getEngineType());
    }
}

在这个汽车制造的场景中,建造者模式同样使得创建汽车对象的过程更加可控和灵活。不同的汽车属性可以通过具体的建造者进行设置,而指挥者则负责协调整个创建过程。这样可以方便地创建不同配置的汽车对象,而无需修改汽车类的构造函数

在框架中的使用

java

在 Java 框架中,建造者模式有很多实际的应用场景,以下是一些例子:

一、java.lang.StringBuilder

StringBuilder是 Java 中用于字符串拼接的类,它使用了建造者模式的思想。 当你使用StringBuilder进行字符串拼接时,你可以逐步地添加字符、字符串等内容,最后通过toString()方法得到最终的字符串结果。

例如:

StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World!");
String result = sb.toString();
System.out.println(result);

这里,StringBuilder就像是一个具体的建造者,通过一系列的方法(如append)来构建最终的字符串(产品)。而客户端只需要调用这些方法来逐步构建字符串,而不需要关心字符串内部是如何存储和拼接的。

二、java.sql.Connection的获取(通过数据库连接池)

在使用数据库连接池时,通常会用到建造者模式的思想。

以常见的数据库连接池库如HikariCP为例,配置数据库连接池时,你可以通过一个建造者对象来设置各种连接参数,如最大连接数、连接超时时间等,最后构建出一个连接池对象。

例如:

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("password");
config.setMaximumPoolSize(10);
HikariDataSource dataSource = new HikariDataSource(config);

这里,HikariConfig就是一个建造者对象,通过设置各种属性来构建出一个HikariDataSource(产品),即数据库连接池。客户端可以方便地通过配置建造者来获得满足特定需求的连接池对象。

三、Lombok 的@Builder注解

Lombok 是一个 Java 库,它通过注解来减少样板代码。其中的@Builder注解在编译时会生成一个建造者模式的实现,使得创建对象更加简洁。例如:

import lombok.Builder;

@Builder
class Product {
    private String name;
    private double price;
}

public class LombokExample {
    public static void main(String[] args) {
        Product product = Product.builder()
               .name("Laptop")
               .price(1000.0)
               .build();
        System.out.println(product.getName() + " " + product.getPrice());
    }
}

使用@Builder注解后,可以通过链式调用的方式设置对象的属性,最后调用build方法创建对象,这是建造者模式的一种简洁实现。

spring

一、BeanDefinitionBuilder

Spring 的BeanDefinitionBuilder是一个用于构建BeanDefinition的工具类,它采用了建造者模式。

例如:

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return BeanDefinitionBuilder.genericBeanDefinition(MyService.class)
               .addPropertyValue("name", "Spring Service")
               .getBeanDefinition().getBean();
    }
}

class MyService {
    private String name;

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

这里使用BeanDefinitionBuilder来构建一个BeanDefinition,并设置了服务类的属性值,然后通过getBeanDefinition().getBean()获取实例化的对象。

mybatis

一、SQL 语句构建器(如SelectBuilder等)

MyBatis 中的动态 SQL 构建也可以看作是建造者模式的一种应用。例如使用SelectBuilder来构建复杂的查询语句。

import org.apache.ibatis.jdbc.SQL;

public class DynamicSqlExample {
    public String buildSelectQuery() {
        return new SQL() {{
            SELECT("id, name, age");
            FROM("users");
            WHERE("age > 18");
            ORDER_BY("name");
        }}.toString();
    }
}

通过逐步调用方法来构建 SQL 语句,使得 SQL 的构建过程更加灵活和可维护,这体现了建造者模式将复杂对象的构建过程分离出来的特点。

总结

优点

  • 封装性好,创建与使用分离
  • 扩展性好,建造类之间独立,一定程度上解耦

建造者和工厂模式的区别

  1. 工厂模式只需要把对象创建出来,而建造者模式需要注意创建需要哪些部件组成
  2. 建造者模式根据建造过程的不一样,最终的对象部件组成也不一样