bboyjing's blog

HeadFirst设计模式十七【建造者模式】

建造者模式描述是:封装一个产品的构造过程,并允许按步骤构造,是在创建一个对象时使用的。我觉得这种模式还是挺常用的,比如Lombok插件的@Builder。下面就来学习下这个模式的细节。

场景描述

假设我们现在要创建一个度假计划,客人可以选择宾馆以及各种门票、餐厅定位,甚至可以选择登记参加特殊的活动。我们正常的构造方式很可能像下面一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Vocation {
/**
* 客人只要求住宾馆的天数,其他随便
*/
public Vocation(Date begin, Date end) {
}
/**
* 客人指定入住宾馆以及入住天数
*/
public Vocation(Date begin, Date end, String hotel) {
}
/**
* 客人指定入住宾馆、天数,以及就餐的餐厅
*/
public Vocation(Date begin, Date end, String hotel, String restaurant) {
}
}

可见这种方式要写好多个构造函数,显得笨重,看看建造者模式如何解决这个问题。

代码示例

  1. 创建Builder类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    public class VocationBuilder {
    private String beginDate;
    private String endDate;
    private String hotel;
    private String restaurant;
    private List<String> tickets;
    /**
    * 指定假期开始时间
    */
    public VocationBuilder setBeginDate(String date) {
    this.beginDate = date;
    return this;
    }
    /**
    * 指定假期结束时间
    */
    public VocationBuilder setEndDate(String date) {
    this.endDate = endDate;
    return this;
    }
    /**
    * 指定入住酒店
    */
    public VocationBuilder setHotel(String hotel) {
    this.hotel = hotel;
    return this;
    }
    /**
    * 指定就餐餐厅
    */
    public VocationBuilder setRestaurant(String restaurant) {
    this.restaurant = restaurant;
    return this;
    }
    /**
    * 指定景点门票
    */
    public VocationBuilder setTicket(List<String> tickets) {
    this.tickets = tickets;
    return this;
    }
    /**
    * 建造出Vocation对象的方法
    */
    public Vocation build() {
    return new Vocation(beginDate, endDate, hotel, restaurant, tickets);
    }
    }
  2. 创建Vocation实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class Vocation {
    private String beginDate;
    private String endDate;
    private String hotel;
    private String restaurant;
    private List<String> tickets;
    public Vocation(String beginDate, String endDate, String hotel, String restaurant, List<String> tickets) {
    this.beginDate = beginDate;
    this.endDate = endDate;
    this.hotel = hotel;
    this.restaurant = restaurant;
    this.tickets = tickets;
    }
    /**
    * 创建builder的静态方法
    */
    public static VocationBuilder builder() {
    return new VocationBuilder();
    }
    @Override
    public String toString() {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder
    .append("BeginDate: ").append(beginDate).append("\n")
    .append("EndDate: ").append(endDate).append("\n")
    .append("Hotel: ").append(hotel).append("\n")
    .append("Restaurant: ").append(restaurant);
    return stringBuilder.toString();
    }
    }
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Test {
    public static void main(String[] args) {
    Vocation vocation = Vocation.builder()
    .setBeginDate("2020/01/01")
    .setEndDate("2018/01/04")
    .setHotel("wanda")
    .setRestaurant("yao")
    .setTicket(new ArrayList<>()).build();
    System.out.println(vocation);
    }
    }

建造者模式实例化对象时优雅多了,其核心内容就是额外多加了一个对应的Builder类,同时在每个set方法中将Builder自身返回,这样可以使用Fluent的方式来构造对象了。建造者模式相对而言还是比较简单的,本章节就到这里了。