本篇文章总结自 【狂神说Java建造者模式】bilibili 狂神说Java建造者模式
- 建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式
- 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象
- 主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
先按照上图写一个Demo,项目结构:
ConnectionPool 是一个连接池对象,其包含了一些属性与 get、set 方法,是一个具体的产品
Builder 是一个抽象的建造者,包含了构建连接池的抽象方法
Worker 是 Builder 的子类,能够返回一个具体的连接池
Director 是指挥 Worker 构建连接池的类
ConnectionPool 的代码:
public class ConnectionPool {
private Integer maxConnNum; //最大连接数量
private Integer minConnNum; //最小连接数量
private Integer initialSize; //初始化连接数量
private Long maxAliveTime; //连接存活时间
// 四个属性的 get、set 方法,这里省略
...
@Override
public String toString() {...}
}
Builder 抽象类:
public abstract class Builder {
abstract void settingMaxConnNum();
abstract void settingMinConnNum();
abstract void settingInitialSize();
abstract void settinMaxAliveTime();
abstract ConnectionPool getConnectionPool();
}
Worker 类,该类在实例化出来的时候就 new 了一个连接池,其四个 setting 方法就是调用连接池对象的 set 方法,还有一个返回连接池实例的方法:
public class Worker extends Builder {
private ConnectionPool pool;
public Worker() {
pool = new ConnectionPool();
}
@Override
void settingMaxConnNum() {
pool.setMaxConnNum(10);
System.out.println("设置最大连接数量为10");
}
@Override
void settingMinConnNum() {
pool.setMinConnNum(1);
System.out.println("设置最小连接数量为1");
}
@Override
void settingInitialSize() {
pool.setInitialSize(5);
System.out.println("设置初始化连接数量为5");
}
@Override
void settinMaxAliveTime() {
pool.setMaxAliveTime(10000L);
System.out.println("设置最大存活时间为10秒");
}
@Override
ConnectionPool getConnectionPool() {
return pool;
}
}
Director 类,指挥类通过调用四个 setting 方法再获取连接池实例:
public class Director {
public static ConnectionPool getConnectionPool(Builder builder) {
builder.settingMaxConnNum();
builder.settingMinConnNum();
builder.settingInitialSize();
builder.settinMaxAliveTime();
return builder.getConnectionPool();
}
}
测试类与结论:
public class Test {
public static void main(String[] args) {
//初始化一个连接池
ConnectionPool pool = Director.getConnectionPool(new Worker());
System.out.println(pool);
}
}
该示例是Builder模式的常规用法,导演类 Director 在 Builder 模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制构建产品的先后次序,并向调用者返回完整的产品类,但是如果要自定义创建一个连接池的时候,我们需要再自定义一个 Worker 类,再通过 Director 去构建,非常麻烦,有些情况下需要简化系统结构,可以把Director和抽象建造者进行结合。
写一个 Demo2,把 Director 的权利交给用户,让用户自己按照需求构建,项目结构:
ConnectionPool 类,在 demo1 基础上赋予了初始值:
public class ConnectionPool {
private Integer maxConnNum = 20; //最大连接数量
private Integer minConnNum = 1; //最小连接数量
private Integer initialSize = 5; //初始化连接数量
private Long maxAliveTime = 10000L; //连接存活时间
// 四个属性的 get、set 方法,这里省略
...
@Override
public String toString() {...}
}
Builder 抽象类,在 demo1 基础上修改方法返回值为自身,方法需传入参数:
public abstract class Builder {
abstract Builder settingMaxConnNum(Integer maxConnNum);
abstract Builder settingMinConnNum(Integer minConnNum);
abstract Builder settingInitialSize(Integer initialSize);
abstract Builder settinMaxAliveTime(Long maxAliveTime);
abstract ConnectionPool getConnectionPool();
}
Worker 类:
public class Worker extends Builder{
private ConnectionPool pool;
public Worker(){
pool = new ConnectionPool();
}
@Override
Builder settingMaxConnNum(Integer maxConnNum) {
pool.setMaxConnNum(maxConnNum);
return this;
}
@Override
Builder settingMinConnNum(Integer minConnNum) {
pool.setMinConnNum(minConnNum);
return this;
}
@Override
Builder settingInitialSize(Integer initialSize) {
pool.setInitialSize(initialSize);
return this;
}
@Override
Builder settinMaxAliveTime(Long maxAliveTime) {
pool.setMaxAliveTime(maxAliveTime);
return this;
}
@Override
ConnectionPool getConnectionPool() {
return pool;
}
}
测试类与结果:
public class Test {
public static void main(String[] args) {
//初始化一个连接池
Worker worker = new Worker();
ConnectionPool pool1 = worker.getConnectionPool();
System.out.println(pool1);
//初始化一个自定义的连接池
ConnectionPool pool2 = worker.settingMaxConnNum(30)
.settingMinConnNum(5)
.settingInitialSize(10)
.settinMaxAliveTime(20000L)
.getConnectionPool();
System.out.println(pool2);
}
}
在第一个案例的基础上,我们将 Director 变成了我们自己,我们可以通过链式编程来构建我们自定义的连接池对象,链式编程也方便用户来构建一个内部负责的对象
建造者模式优点:
- 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节
- 将复杂产品的创建步骤分解在不同的方法中, 使得创建过程更加清晰
- 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合“开闭原则”
建造者模式缺点: - 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
- 如果产品的内部变化复杂, 可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大
应用场景:
- 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
- 适合于一个具有较多属性的类的创建过程。
建造者与抽象工厂模式的比较:
- 与抽象工厂模式相比,建造者模式返回-个组装好的完整产品,而抽象工厂模式返回一系列相关的产品(某个厂商生产的手机、路由器),这些产品位于不同的产品等级结构,构成了一个产品族(例如小米生态中的各种产品)
- 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象;而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象, 返回一个完整的对象
- 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车