# 建造者模式

**一般在什么场景下使用建造者模式？**

①需要的这个对象非常复杂，即它包含非常多的属性

②对象构建出来就保持不变或很少改变

符合此类要求的我能想到的就是一些配置类或者其他一些工具库。如[Spring-Data-Redis](https://github.com/spring-projects/spring-data-redis)中[JedisClientConfiguration](https://github.com/spring-projects/spring-data-redis/blob/master/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientConfiguration.java)或者[Picasso](http://square.github.io/picasso/)中的[Picasso](https://github.com/square/picasso/blob/master/picasso/src/main/java/com/squareup/picasso3/Picasso.java)中就使用了建造者模式，可以通过以下代码感受一些使用建造者模式创建对象的方式：

```java
//获取JedisClientConfiguration的方式
public JedisClientConfiguration jedisClientConfiguration() {

        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder configurationBuilder = (
                JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();

        GenericObjectPoolConfig GenericObjectPoolConfig = new GenericObjectPoolConfig();
        GenericObjectPoolConfig.setMaxIdle(1000);
        GenericObjectPoolConfig.setMaxTotal(100);
        GenericObjectPoolConfig.setMinIdle(100);

        return configurationBuilder
                .poolConfig(GenericObjectPoolConfig)
                .and()
                .usePooling()//显式指明使用pool
                .build();
}

//Picasso的使用方式
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
```

使用建造者模式的一般步骤或思想

①最终对象一般都比较复杂，构建过程中可能需要其他对象；

②一般将必要参数设置在构建builder的方法中，再由build为最终对象设置非必须参数

③最后由build()方法返回最终对象

**实例1**&#x20;

[代码来源](https://www.jianshu.com/p/e2a2fe3555b9)

```java
public class User {

    private final String firstName;     // 必传参数
    private final String lastName;      // 必传参数
    private final int age;              // 可选参数
    private final String phone;         // 可选参数
    private final String address;       // 可选参数

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }

    public static class UserBuilder {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;

        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }

        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}
```

使用方式：

```
User user = new User.UserBuilder("王", "小二")
                .age(20)
                .phone("123456789")
                .address("亚特兰蒂斯大陆")
                .build();
```

**实例2**

[代码来源](https://github.com/spring-projects/spring-data-redis/blob/master/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientConfiguration.java)

```
public interface JedisClientConfiguration {

    boolean isUseSsl();

    Optional<SSLSocketFactory> getSslSocketFactory();

    Optional<SSLParameters> getSslParameters();

    Optional<HostnameVerifier> getHostnameVerifier();

    boolean isUsePooling();

    Optional<GenericObjectPoolConfig> getPoolConfig();

    Optional<String> getClientName();

    Duration getConnectTimeout();

    Duration getReadTimeout();

    static JedisClientConfigurationBuilder builder() {
        return new DefaultJedisClientConfigurationBuilder();
    }

    /**
     * Creates a default {@link JedisClientConfiguration}.
     * <dl>
     * <dt>SSL enabled</dt>
     * <dd>no</dd>
     * <dt>Pooling enabled</dt>
     * <dd>no</dd>
     * <dt>Client Name</dt>
     * <dd>[not set]</dd>
     * <dt>Read Timeout</dt>
     * <dd>2000 msec</dd>
     * <dt>Connect Timeout</dt>
     * <dd>2000 msec</dd>
     * </dl>
     *
     * @return a {@link JedisClientConfiguration} with defaults.
     */
    static JedisClientConfiguration defaultConfiguration() {
        return builder().build();
    }

    /**
     * Builder for {@link JedisClientConfiguration}.
     */
    interface JedisClientConfigurationBuilder {

        JedisSslClientConfigurationBuilder useSsl();

        JedisPoolingClientConfigurationBuilder usePooling();

        JedisClientConfigurationBuilder clientName(String clientName);

        JedisClientConfigurationBuilder readTimeout(Duration readTimeout);

        JedisClientConfigurationBuilder connectTimeout(Duration connectTimeout);

        JedisClientConfiguration build();
    }

    /**
     * Builder for Pooling-related {@link JedisClientConfiguration}.
     */
    interface JedisPoolingClientConfigurationBuilder {

        JedisPoolingClientConfigurationBuilder poolConfig(GenericObjectPoolConfig poolConfig);

        JedisClientConfigurationBuilder and();

        JedisClientConfiguration build();
    }

    /**
     * Builder for SSL-related {@link JedisClientConfiguration}.
     */
    interface JedisSslClientConfigurationBuilder {

        JedisSslClientConfigurationBuilder sslSocketFactory(SSLSocketFactory sslSocketFactory);

        JedisSslClientConfigurationBuilder sslParameters(SSLParameters sslParameters);

        JedisSslClientConfigurationBuilder hostnameVerifier(HostnameVerifier hostnameVerifier);

        JedisClientConfigurationBuilder and();

        JedisClientConfiguration build();
    }


    class DefaultJedisClientConfigurationBuilder implements JedisClientConfigurationBuilder,
            JedisPoolingClientConfigurationBuilder, JedisSslClientConfigurationBuilder {

        private boolean useSsl;
        private @Nullable SSLSocketFactory sslSocketFactory;
        private @Nullable SSLParameters sslParameters;
        private @Nullable HostnameVerifier hostnameVerifier;
        private boolean usePooling;
        private GenericObjectPoolConfig poolConfig = new JedisPoolConfig();
        private @Nullable String clientName;
        private Duration readTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT);
        private Duration connectTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT);

        private DefaultJedisClientConfigurationBuilder() {}

        @Override
        public JedisSslClientConfigurationBuilder useSsl() {
            this.useSsl = true;
            return this;
        }

        @Override
        public JedisSslClientConfigurationBuilder sslSocketFactory(SSLSocketFactory sslSocketFactory) {
            this.sslSocketFactory = sslSocketFactory;
            return this;
        }

        @Override
        public JedisSslClientConfigurationBuilder sslParameters(SSLParameters sslParameters) {
            this.sslParameters = sslParameters;
            return this;
        }

        @Override
        public JedisSslClientConfigurationBuilder hostnameVerifier(HostnameVerifier hostnameVerifier) {
            this.hostnameVerifier = hostnameVerifier;
            return this;
        }

        @Override
        public JedisPoolingClientConfigurationBuilder usePooling() {
            this.usePooling = true;
            return this;
        }

        @Override
        public JedisPoolingClientConfigurationBuilder poolConfig(GenericObjectPoolConfig poolConfig) {
            this.poolConfig = poolConfig;
            return this;
        }

        @Override
        public JedisClientConfigurationBuilder and() {
            return this;
        }

        @Override
        public JedisClientConfigurationBuilder clientName(String clientName) {
            this.clientName = clientName;
            return this;
        }

        @Override
        public JedisClientConfigurationBuilder readTimeout(Duration readTimeout) {
            this.readTimeout = readTimeout;
            return this;
        }

        @Override
        public JedisClientConfigurationBuilder connectTimeout(Duration connectTimeout) {
            this.connectTimeout = connectTimeout;
            return this;
        }

        @Override
        public JedisClientConfiguration build() {
            return new DefaultJedisClientConfiguration(useSsl, sslSocketFactory, sslParameters, hostnameVerifier, usePooling,
                    poolConfig, clientName, readTimeout, connectTimeout);
        }
    }

}
```

## 参考

[设计模式之Builder模式](https://www.jianshu.com/p/e2a2fe3555b9)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://maxwell.gitbook.io/way-to-architect/she-ji-mo-shi/chuang-jian-xing/jian-zao-zhe-mo-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
