设计模式-Builder模式

建造者模式(Builder pattern)通过将一个复杂对象的构建过程与它的表现分离,使得构建的过程可以自由扩展,降低部件与组装过程的耦合,是创建型模式。

考虑这样一个场景,假如有一个类(User),里面有很多属性,并且你希望这些类的属性都是不可变的(final),就像下面的代码。

public class User {

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

在这个类中,有些参数是必要的,而有些参数是非必要的,就好比在注册用户时,用户的姓和名是必填的,而年龄、手机号和家庭地址等是非必需要。那么问题就来了,如何创建这个类的对象呢?

一种方案是使用构造方法。第一个构造方法只包含两个必需要参数,第二个构造方法中,增加一个可选参数,第三个构造方法中再增加一个可选参数,依次类推,直到构造方法中包含了所有参数。

public User(String firstName, String lastName) {
        this(firstName, lastName, 0);
    }

    public User(String firstName, String lastName, int age) {
        this(firstName, lastName, age, "");
    }

    public User(String firstName, String lastName, int age, String phone) {
        this(firstName, lastName, age, phone, "");
    }

    public User(String firstName, String lastName, int age, String phone, String address) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }

弊端:

(1)一旦参数多了,代码可读性就差,并且难以维护。

(2)对调用者来说麻烦。

第二种解决方案,就是设置一个空参数的构造方法,然后为每一个属性设置setters和getters。

public class User {

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

    public User() {
    }

    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;
    }
}

弊端:

(1)不可变类的所有好处都不复存在。

(2)对象会产生不一致的状态,当你想要传入5个参数的时候,你必须将所有的setxx方法调用完成之后才行,然而一部分的调用者看到这个对象后,以为这个对象已创建完毕,就直接使用了,其实User对象并没有创建完成。

现在我们使用Builder模式

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);
        }
    }
}

有现个重要的地方需要强调一下:

(1)User类的构造方法是私有的,也就是说调用者不能直接创建User对象。

(2)User类的属性都是不可变的,所有的属性都添加了final修饰符,并且在构造方法中设置了值,并且,对外只提供getters方法。

(3)Builder模式使用了链式调用,可读性更佳。

(4)Builder的内部类构造方法中只接收必传的参数,并且该必传的参数使用final修饰符。

 

经典Builder模式

之前实例中的Builder模式,是省略掉了装饰者模式,这样结构更加简单,所以在很多开源框架源码中,大多都不是经典GOF的Builder模式,而省略后的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值