基本概念

简单描述

建造者模式是一种用来创建具有复杂类型的对象(比如汽车,需要各种零件组装构成—复杂)所使用的设计模式。可以设置不同的可选参数,定制化地创建不同的对象(比如:有天窗的汽车,能容纳7个人的汽车,双排气筒,马力够的汽车等)。

应用场景

1、一个对象有多个成员变量,且部分成员变量存在默认值(可选),使用构造函数和set方法造成可读性差的问题;
2、对象初始参数过多,直接用构造函数new出来,代码不够简洁,容易出错;
3、直接使用默认构造函数new出对象,再采用set方法为成员赋值,可能会产生一种情况:在所有的成员变量都没有赋值成功之前,对象属于无效状态(例如对象长方形,需要等待长和宽的值都set成功);
4、需要一次性创建具有相互依赖关系的多个对象时,需要在对象创建完成前验证成员变量的约束条件时;希望最终创建的对象是不可变对象的情况下,不能在类中暴露set方法。

以上几种情况下,就可以使用到建造者模式。

具体实现示例

以下代码参照 极客时间:设计模式之美

  1. public class ResourcePoolConfig {
  2. private String name;
  3. private int maxTotal;
  4. private int maxIdle;
  5. private int minIdle;
  6. public ResourcePoolConfig(Builder builder) {
  7. this.name = builder.name;
  8. this.maxTotal = builder.maxTotal;
  9. this.maxIdle = builder.maxIdle;
  10. this.minIdle = builder.minIdle;
  11. }
  12. public static ResourcePoolConfig.Builder newBuilder() {
  13. return new ResourcePoolConfig.Builder();
  14. }
  15. public static class Builder {
  16. private static final int DEFAULT_MAX_TOTAL = 8;
  17. private static final int DEFAULT_MAX_IDLE = 8;
  18. private static final int DEFAULT_MIN_IDLE = 0;
  19. private String name;
  20. private int maxTotal = DEFAULT_MAX_TOTAL;
  21. private int maxIdle = DEFAULT_MAX_IDLE;
  22. private int minIdle = DEFAULT_MIN_IDLE;
  23. public ResourcePoolConfig build() {
  24. // 校验逻辑:包括必填项校验、依赖关系校验、约束条件校验等
  25. if (StringUtils.isBlank(name)) {
  26. throw new IllegalArgumentException("...");
  27. }
  28. if(maxIdle > maxTotal) {
  29. throw new IllegalArgumentException("...");
  30. }
  31. ...
  32. return new ResourcePoolConfig(this);
  33. }
  34. public Builder setName(String name) {
  35. if(StringUtils.isBlank(name)) {
  36. throw new IllegalArgumentException("...");
  37. }
  38. this.name = name;
  39. return this;
  40. }
  41. public Builder setMaxTotal(int maxTotal) {
  42. if(maxTotal <= 0) {
  43. throw new IllegalArgumentException("...");
  44. }
  45. this.maxTotal = maxTotal;
  46. return this;
  47. }
  48. public Builder setMaxIdle(int maxIdle) {
  49. if(maxIdle <= 0) {
  50. throw new IllegalArgumentException("...");
  51. }
  52. this.maxIdle = maxIdle;
  53. return this;
  54. }
  55. public Builder setMinIdle(int minIdle) {
  56. if(minIdle <= 0) {
  57. throw new IllegalArgumentException("...");
  58. }
  59. this.minIdle = minIdle;
  60. return this;
  61. }
  62. }
  63. }
  64. public static void main(String[] args) {
  65. ResourcePoolConfig config = new ResourcePoolConfig.Builder()
  66. .setName("name")
  67. .setMaxTotal(16)
  68. .setMaxIdle(10)
  69. .setMinIdle(8)
  70. .build();
  71. }

业务场景

微信支付请求参数封装

基于微信JSAPI支付请求参数的封装

实现构造者模式步骤

  1. ## 外部类
  2. 1、构造方法, public WxJsApiRequest(builder)
  3. 2、调用静态内部类构造方法的静态方法:WxJsApiRequest.newBuilder
  4. 1、静态内部类 Builder
  5. 2、构造方法 public Builder()
  6. 3、静态内部类 Builder细节
  7. - 以成员变量为方法名称,形参为成员变量,返回值为Builder实例,方法代码块内部可添加约束条件
  8. - 内部非静态方法(普通方法)build,内部构造WxJsAPiRequest实例对象new WxJsApiRequest(builder)

Request对象封装

  1. package com.cmic.model;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.alibaba.fastjson.annotation.JSONField;
  4. import lombok.Getter;
  5. import java.io.Serializable;
  6. import java.util.List;
  7. /**
  8. * 建造者模式
  9. * 1、静态内部类 Builder
  10. * 2、调用静态内部类构造方法的静态方法:WxJsApiRequest.newBuilder
  11. * 3、静态内部类 Builder细节
  12. * - 以成员变量为方法名称,形参为成员变量,返回值为Builder实例
  13. * - 内部非静态方法(普通方法)build,内部 构造WxJsAPiRequest实例对象,new WxJsApiRequest(build)
  14. */
  15. @Getter
  16. public class WxJsApiRequest implements Serializable {
  17. private static final long serialVersionUID = 1L;
  18. private String appId;
  19. private String mchId;
  20. private String description;
  21. private String outTradeNo;
  22. private String timeExpire;
  23. private String attach;
  24. private String notifyUrl;
  25. private String goodsTag;
  26. private WxAmount amount;
  27. private JSONObject payer;
  28. private WxDetail detail;
  29. private JSONObject sceneInfo;
  30. private JSONObject settleInfo;
  31. WxJsApiRequest() {
  32. }
  33. WxJsApiRequest(Builder builder) {
  34. this.appId = builder.appId;
  35. this.mchId = builder.mchId;
  36. this.description = builder.description;
  37. this.outTradeNo = builder.outTradeNo;
  38. this.timeExpire = builder.timeExpire;
  39. this.attach = builder.attach;
  40. this.notifyUrl = builder.notifyUrl;
  41. this.goodsTag = builder.goodsTag;
  42. this.amount = new WxAmount(builder);
  43. this.payer = builder.payer;
  44. this.detail = new WxDetail(builder);
  45. this.sceneInfo = builder.sceneInfo;
  46. this.settleInfo = builder.settleInfo;
  47. }
  48. @Override
  49. public String toString() {
  50. return "WxJsApiRequest{" +
  51. "appId='" + appId + '\'' +
  52. ", mchId='" + mchId + '\'' +
  53. ", description='" + description + '\'' +
  54. ", outTradeNo='" + outTradeNo + '\'' +
  55. ", timeExpire='" + timeExpire + '\'' +
  56. ", attach='" + attach + '\'' +
  57. ", notifyUrl='" + notifyUrl + '\'' +
  58. ", goodsTag='" + goodsTag + '\'' +
  59. ", amount=" + amount +
  60. ", payer=" + payer +
  61. ", detail=" + detail +
  62. ", sceneInfo=" + sceneInfo +
  63. ", settleInfo=" + settleInfo +
  64. '}';
  65. }
  66. public static WxJsApiRequest.Builder newBuilder() {
  67. return new WxJsApiRequest.Builder();
  68. }
  69. public static class Builder {
  70. private String appId;
  71. private String mchId;
  72. private String description;
  73. private String outTradeNo;
  74. private String timeExpire;
  75. private String attach;
  76. private String notifyUrl;
  77. private String goodsTag;
  78. private Integer total;
  79. private String currency;
  80. private JSONObject payer;
  81. private Integer costPrice;
  82. private List<String> goodsDetail;
  83. private JSONObject sceneInfo;
  84. private JSONObject settleInfo;
  85. private Builder() {
  86. }
  87. public WxJsApiRequest.Builder appId(String appId) {
  88. this.appId = appId;
  89. return this;
  90. }
  91. public WxJsApiRequest.Builder mchId(String mchId) {
  92. this.mchId = mchId;
  93. return this;
  94. }
  95. public WxJsApiRequest.Builder description(String description) {
  96. this.description = description;
  97. return this;
  98. }
  99. public WxJsApiRequest.Builder outTradeNo(String outTradeNo) {
  100. this.outTradeNo = outTradeNo;
  101. return this;
  102. }
  103. public WxJsApiRequest.Builder timeExpire(String timeExpire) {
  104. this.timeExpire = timeExpire;
  105. return this;
  106. }
  107. public WxJsApiRequest.Builder attach(String attach) {
  108. this.attach = attach;
  109. return this;
  110. }
  111. public WxJsApiRequest.Builder notifyUrl(String notifyUrl) {
  112. this.notifyUrl = notifyUrl;
  113. return this;
  114. }
  115. public WxJsApiRequest.Builder goodsTag(String goodsTag) {
  116. this.goodsTag = goodsTag;
  117. return this;
  118. }
  119. public WxJsApiRequest.Builder total(Integer total) {
  120. this.total = total;
  121. return this;
  122. }
  123. public WxJsApiRequest.Builder currency(String currency) {
  124. this.currency = currency;
  125. return this;
  126. }
  127. public WxJsApiRequest.Builder payer(JSONObject payer) {
  128. this.payer = payer;
  129. return this;
  130. }
  131. public WxJsApiRequest.Builder costPrice(Integer costPrice) {
  132. // todo: 成员变量的约束,比如 costPrice>0
  133. this.costPrice = costPrice;
  134. return this;
  135. }
  136. public WxJsApiRequest.Builder goodsDetail(List<String> goodsDetail) {
  137. this.goodsDetail = goodsDetail;
  138. return this;
  139. }
  140. public WxJsApiRequest.Builder sceneInfo(JSONObject sceneInfo) {
  141. this.sceneInfo = sceneInfo;
  142. return this;
  143. }
  144. public WxJsApiRequest.Builder settleInfo(JSONObject settleInfo) {
  145. this.settleInfo = settleInfo;
  146. return this;
  147. }
  148. public WxJsApiRequest build() {
  149. // todo: 成员变量之间的约束条件, 比如 total > costPrice
  150. return new WxJsApiRequest(this);
  151. }
  152. }
  153. @Getter
  154. private static class WxAmount {
  155. private Integer total;
  156. private String currency;
  157. private WxAmount(Builder builder) {
  158. this.total = builder.total;
  159. this.currency = builder.currency;
  160. }
  161. }
  162. @Getter
  163. private class WxDetail {
  164. private Integer costPrice;
  165. private List<String> goodsDetail;
  166. private WxDetail(Builder builder) {
  167. this.costPrice = builder.costPrice;
  168. this.goodsDetail = builder.goodsDetail;
  169. }
  170. }
  171. }

具体调用处理

  1. @RequestMapping(value = "test", method = RequestMethod.GET)
  2. public WxJsApiRequest test() {
  3. WxPayConfig instance = WxPayConfig.getInstance();
  4. WxPayParamConf wxPayParamConf = instance.getWxPayParamConf();
  5. System.out.println(JSON.toJSONString(wxPayParamConf));
  6. List<String> goodsDetail = new ArrayList<>();
  7. goodsDetail.add("test1");
  8. goodsDetail.add("test2");
  9. JSONObject payer = new JSONObject();
  10. payer.put("openid", "oa6sh5Q_tRltHkl11CJE-MF4GZ64");
  11. WxJsApiRequest wxJsApiRequest = WxJsApiRequest.newBuilder()
  12. .appId("wxe97be9fe6f5b66cb")
  13. .mchId("1421036202")
  14. .description("测试商品")
  15. .outTradeNo("P1234546")
  16. .timeExpire("2021-06-16 16:55:00")
  17. .notifyUrl("http://qa.weimi24.com/wxReceiver")
  18. .total(2) // amout相关-总金额
  19. .currency("CNY") // amount相关-货币类型
  20. .payer(payer)
  21. .costPrice(1)
  22. .goodsDetail(goodsDetail)
  23. .build();
  24. System.out.println(JSON.toJSONString(wxJsApiRequest));
  25. System.out.println(wxJsApiRequest.toString());
  26. return wxJsApiRequest;
  27. }