项目知识点整理——设计模式部分


Java中的Builder模式

作为一只小白,在看到下面这样额的代码时,还真是一脸懵逼。。。

 new IncomingGarmentStatBuilder()
                        .id(UUID.randomUUID())
                        .endDateInRange(toDate)
                        .range(DAILY)
                        .org(organization)
                        .value(sumValueByOrg(dailyOnceStats, organization))
                        .build()

虽然可以猜到是在创建新对象,但是这种方式还真是诡异呢


项目知识点整理——设计模式部分_第1张图片
什么鬼?

再加上当这段代码混在java 8 的stream处理过程中时,像下面这样,

 List dailyStats = organizations.stream()
                .map(organization ->
                new IncomingGarmentStatBuilder()
                        .id(UUID.randomUUID())
                        .endDateInRange(toDate)
                        .range(DAILY)
                        .org(organization)
                        .value(sumValueByOrg(dailyOnceStats, organization))
                        .build())
                .collect(Collectors.toList());

不学无术的我更难以理解这一堆方法调用是在干什么了。。。

项目知识点整理——设计模式部分_第2张图片
这是在干嘛?

不过没有关系,看不懂这一堆方法调用,可以一个一个来。
可以从对我而言比较奇怪的这个Builder类的构造方法入手,点进去看看就好了。
这不看还好,一看真是吓一跳。这个Builder类长成了这个样子:

public class IncomingGarmentStatBuilder {
    private IncomingGarmentStat incomingGarmentStat;

    public IncomingGarmentStatBuilder() {
        incomingGarmentStat = new IncomingGarmentStat();
    }

    public IncomingGarmentStatBuilder(IncomingGarmentStat incomingGarmentStat) {
        this.incomingGarmentStat = incomingGarmentStat;
    }

    public IncomingGarmentStat build() {
        return incomingGarmentStat;
    }

    public IncomingGarmentStatBuilder id(UUID id) {
        incomingGarmentStat.setId(id);
        return this;
    }

    public IncomingGarmentStatBuilder range(StatisticRange range) {
        incomingGarmentStat.setRange(range);
        return this;
    }
....
}

可以看出,这个Builder类是对所构造的类的set方法在此进行了一次封装,使得可以通过调用与属性名相同的方法名为当前所构建的对象set属性值。
那么问题来了,当我在创建一个实体类,一般也就是一个Java Bean时,都会设计这个类的get、set方法,并通过这些方法给所要创建的对象赋值。
简单来说,例如对于一个People类而言,

public class People {
  
   private int id;
   private String name;
   private int age;
   private String gender;

  public People() {
  }

  public People(int id, String name, int age, String gender) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.gender = gender;
  }

  public setId(int id) {
    this.id = id;
  }

  public getId() {
    return id;
  }

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

  public getName() {
    return name;
  }
  
  public setAge(int age) {
    this.age = age;
  }

  public getAge() {
    return age;
  }

  public setGender(String gender) {
    this.gender = gender;
  }

  public getGender() {
    return gender;
  }
}

一般都长成上面这样。按照这种大众化的People类的设计方式,我去创建一个新的People对象时,可以有两种方法:

  • 直接调用构造方法,把给定的参数通过构造方法传入,如下:
    People person = new People(9527, "华安", 24, "男");
  • 通过新建一个空对象使用set方法完成对象构建,如下:
People person = new People();
person.setId(9527);
person.setName("华安");
person.setAge(24);
person.setGender("男");

这两种方法也是我常用的方法。其实对于上述例子中的People,因为属性较少,我们通过上述的两种方式去创建实例对象都还较为方便易懂。但可以设想一下,若对于一个含有多种属性的复杂类而言,使用这种构造器传参或者使用set方法完成初始化实例对象的工作会带来什么问题?

  1. 对于通过构造器传参创建新对象,在参数较多的情况下,会使得传入参数和其对应的参数含义分离,对于读代码的人而言,不会一下就能明白这些参数的意义何在。
  2. 对于set方法传参而言,显而易见的是在大量属性需要set的情况下,需要调用多种的set方法,从而使得在构建一个对象的过程中,使得代码过于冗长。

因此,Builder类的采用,也就是建造者模式可以再保证代码可读性的前提下,使对象的创建变得灵活、简洁。对于上述的People类,采用建造者模式后,其PeopleBuilder类设计如下:

public class PeopleBuilder {
  private People person;
  
  public PeopleBuilder() {
    person = new People();
  }

  public PeopleBuilder(People person) {
    this.person = person; 
  }

  public PeopleBuilder id(int id) {
    person.setId(id);
    return this;
  }

   public PeopleBuilder name(String name) {
    person.setName(name);
    return this; 
  }

  public PersonBuilder age(int age) {
    person.setAge(age);
    return this;
  }

  public PersonBuilder gender(String gender) {
    person.setGender(gender);
    return this;
  }

  public People build() {
    return person;
  }
}

如此一来,如果要创建一个People对象,就可以用如下方式:

People person = new PeopleBuilder().id(9527)
                                   .name("华安")
                                   .age(24)
                                   .gender("男")
                                   .build();

如此一来相比之前的set方法就可以显得十分简洁明了。并且当这种方式嵌入到Stream的处理流中,或者Lambda表达式中时,也是毫无违和感的。
这就是建造者模式在Java中的使用了。

你可能感兴趣的:(项目知识点整理——设计模式部分)