关注「Java视界」公众号,获取更多技术干货

建造者模式(Builder pattern)—— 帮你更好的创建复杂对象

建造者模式是将一个复杂对象的构建与它的表示分离,各自独立,同样的构建过程可以有不同的表现。 

一、你会怎么办?

对于复杂对象,那假如一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,你要怎样将这个类实例化?可以有两种方式:

比如我们要画一个人,这个人有头、手、脚、身体这些必选项,也有衣服、鞋子、帽子这些可选项。

public class PersonDraw1 {
    // 必选属性
    private String head;
    private String hand;
    private String foot;
    private String body;
    // 可选项
    private String clothes;
    private String shoes;
    private String hat;
}

 第一种:折叠构造方法模式

public class PersonDraw1 {
    // 必选属性
    private String head;
    private String hand;
    private String foot;
    private String body;
    // 可选项
    private String clothes;
    private String shoes;
    private String hat;

    public PersonDraw1(String head, String hand, String foot, String body) {
        this.head = head;
        this.hand = hand;
        this.foot = foot;
        this.body = body;
    }

    public PersonDraw1(String head, String hand, String foot, String body, String clothes) {
        this.head = head;
        this.hand = hand;
        this.foot = foot;
        this.body = body;
        this.clothes = clothes;
    }

    public PersonDraw1(String head, String hand, String foot, String body, String clothes, String shoes) {
        this.head = head;
        this.hand = hand;
        this.foot = foot;
        this.body = body;
        this.clothes = clothes;
        this.shoes = shoes;
    }

    public PersonDraw1(String head, String hand, String foot, String body, String clothes, String shoes, String hat) {
        this.head = head;
        this.hand = hand;
        this.foot = foot;
        this.body = body;
        this.clothes = clothes;
        this.shoes = shoes;
        this.hat = hat;
    }
}

第二种:Javabean 模式

@Getter
@Setter
public class PersonDraw1 {
    // 必选属性
    private String head;
    private String hand;
    private String foot;
    private String body;
    // 可选项
    private String clothes;
    private String shoes;
    private String hat;
}

第一种:调用一个类的构造函数时要决定使用哪一个,且还要考虑参数含义及顺序。

第二种:在构建过程中对象的状态容易发生变化,造成错误。

以上两种方式在创建对象时,可能造成对象不完整,少了某个属性或流程。要是少了必选项这个对象就没意义了,比如这个人缺胳膊少腿。

二、建造者模式

上面的问题,使用建造者模式可以解决。

@Getter
@ToString
public class PersonDraw {
    // 必选属性
    private String head;
    private String hand;
    private String foot;
    private String body;
    // 可选项
    private String clothes;
    private String shoes;
    private String hat;

    public PersonDraw(Builder builder){
        this.head = builder.head;
        this.hand = builder.hand;
        this.foot = builder.foot;
        this.body = builder.body;
        this.clothes = builder.clothes;
        this.shoes = builder.shoes;
        this.hat = builder.hat;
    }

    public static class Builder {
        // 必选属性
        private String head;
        private String hand;
        private String foot;
        private String body;
        // 可选项
        private String clothes;
        private String shoes;
        private String hat;

        public Builder (String head, String hand, String foot, String body){
            this.head = head;
            this.hand = hand;
            this.foot = foot;
            this.body = body;
        }

        public Builder setClothes(String clothes){
            this.clothes = clothes;
            return this;
        }

        public Builder setShoes(String shoes) {
            this.shoes = shoes;
            return this;
        }

        public Builder setHat(String hat) {
            this.hat = hat;
            return this;
        }

        public PersonDraw build(){
            return new PersonDraw(this);
        }
    }
}
public class Client {
    public static void main(String[] args) {
        PersonDraw personDraw = new PersonDraw.Builder("头", "手", "脚", "身体")
                .setClothes("衣服")
                .build();
        Console.log(personDraw.toString());
        Console.log(personDraw.getFoot());
    }
}
PersonDraw(head=头, hand=手, foot=脚, body=身体, clothes=衣服, shoes=null, hat=null)
脚
  1. 在 PersonDraw 中创建一个静态内部类 Builder,然后将 PersonDraw 中的参数都复制到Builder类中。
  2. 在 PersonDraw 中创建一个private的构造函数,参数为Builder类型。
  3. 在Builder中创建一个构造函数,参数为 PersonDraw 中必填的那些参数。
  4. 在Builder中创建设置函数,对那些可选参数进行赋值,返回值为Builder类型的实例。
  5. 在Builder中创建一个build()方法,在其中构建 PersonDraw 的实例并返回。

三、建造者模式适用场景

优点:

  1.客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

  2.每一个具体建造者都独立,因此可以方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。

  3.可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰。

缺点:

  1.当建造者过多时,会产生很多类,难以维护。

  2.建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,若产品之间的差异性很大,则不适合使用该模式。

  3.若产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

适用场景:

       1.创建复杂对象的算法独立于组成对象的部件

       2.同一个创建过程需要有不同的内部表象的产品对象

但一般当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

posted @ 2022-06-25 14:02  沙滩de流沙  阅读(27)  评论(0编辑  收藏  举报

关注「Java视界」公众号,获取更多技术干货