基本概念
简单描述
建造者模式是一种用来创建具有复杂类型的对象(比如汽车,需要各种零件组装构成—复杂)所使用的设计模式。可以设置不同的可选参数,定制化地创建不同的对象(比如:有天窗的汽车,能容纳7个人的汽车,双排气筒,马力够的汽车等)。
应用场景
1、一个对象有多个成员变量,且部分成员变量存在默认值(可选),使用构造函数和set方法造成可读性差的问题;
2、对象初始参数过多,直接用构造函数new出来,代码不够简洁,容易出错;
3、直接使用默认构造函数new出对象,再采用set方法为成员赋值,可能会产生一种情况:在所有的成员变量都没有赋值成功之前,对象属于无效状态(例如对象长方形,需要等待长和宽的值都set成功);
4、需要一次性创建具有相互依赖关系的多个对象时,需要在对象创建完成前验证成员变量的约束条件时;希望最终创建的对象是不可变对象的情况下,不能在类中暴露set方法。
以上几种情况下,就可以使用到建造者模式。
具体实现示例
以下代码参照 极客时间:设计模式之美
public class ResourcePoolConfig {private String name;private int maxTotal;private int maxIdle;private int minIdle;public ResourcePoolConfig(Builder builder) {this.name = builder.name;this.maxTotal = builder.maxTotal;this.maxIdle = builder.maxIdle;this.minIdle = builder.minIdle;}public static ResourcePoolConfig.Builder newBuilder() {return new ResourcePoolConfig.Builder();}public static class Builder {private static final int DEFAULT_MAX_TOTAL = 8;private static final int DEFAULT_MAX_IDLE = 8;private static final int DEFAULT_MIN_IDLE = 0;private String name;private int maxTotal = DEFAULT_MAX_TOTAL;private int maxIdle = DEFAULT_MAX_IDLE;private int minIdle = DEFAULT_MIN_IDLE;public ResourcePoolConfig build() {// 校验逻辑:包括必填项校验、依赖关系校验、约束条件校验等if (StringUtils.isBlank(name)) {throw new IllegalArgumentException("...");}if(maxIdle > maxTotal) {throw new IllegalArgumentException("...");}...return new ResourcePoolConfig(this);}public Builder setName(String name) {if(StringUtils.isBlank(name)) {throw new IllegalArgumentException("...");}this.name = name;return this;}public Builder setMaxTotal(int maxTotal) {if(maxTotal <= 0) {throw new IllegalArgumentException("...");}this.maxTotal = maxTotal;return this;}public Builder setMaxIdle(int maxIdle) {if(maxIdle <= 0) {throw new IllegalArgumentException("...");}this.maxIdle = maxIdle;return this;}public Builder setMinIdle(int minIdle) {if(minIdle <= 0) {throw new IllegalArgumentException("...");}this.minIdle = minIdle;return this;}}}public static void main(String[] args) {ResourcePoolConfig config = new ResourcePoolConfig.Builder().setName("name").setMaxTotal(16).setMaxIdle(10).setMinIdle(8).build();}
业务场景
微信支付请求参数封装
实现构造者模式步骤
## 外部类1、构造方法, public WxJsApiRequest(builder)2、调用静态内部类构造方法的静态方法:WxJsApiRequest.newBuilder1、静态内部类 Builder2、构造方法 public Builder()3、静态内部类 Builder细节- 以成员变量为方法名称,形参为成员变量,返回值为Builder实例,方法代码块内部可添加约束条件- 内部非静态方法(普通方法)build,内部构造WxJsAPiRequest实例对象new WxJsApiRequest(builder)
Request对象封装
package com.cmic.model;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.annotation.JSONField;import lombok.Getter;import java.io.Serializable;import java.util.List;/*** 建造者模式* 1、静态内部类 Builder* 2、调用静态内部类构造方法的静态方法:WxJsApiRequest.newBuilder* 3、静态内部类 Builder细节* - 以成员变量为方法名称,形参为成员变量,返回值为Builder实例* - 内部非静态方法(普通方法)build,内部 构造WxJsAPiRequest实例对象,new WxJsApiRequest(build)*/@Getterpublic class WxJsApiRequest implements Serializable {private static final long serialVersionUID = 1L;private String appId;private String mchId;private String description;private String outTradeNo;private String timeExpire;private String attach;private String notifyUrl;private String goodsTag;private WxAmount amount;private JSONObject payer;private WxDetail detail;private JSONObject sceneInfo;private JSONObject settleInfo;WxJsApiRequest() {}WxJsApiRequest(Builder builder) {this.appId = builder.appId;this.mchId = builder.mchId;this.description = builder.description;this.outTradeNo = builder.outTradeNo;this.timeExpire = builder.timeExpire;this.attach = builder.attach;this.notifyUrl = builder.notifyUrl;this.goodsTag = builder.goodsTag;this.amount = new WxAmount(builder);this.payer = builder.payer;this.detail = new WxDetail(builder);this.sceneInfo = builder.sceneInfo;this.settleInfo = builder.settleInfo;}@Overridepublic String toString() {return "WxJsApiRequest{" +"appId='" + appId + '\'' +", mchId='" + mchId + '\'' +", description='" + description + '\'' +", outTradeNo='" + outTradeNo + '\'' +", timeExpire='" + timeExpire + '\'' +", attach='" + attach + '\'' +", notifyUrl='" + notifyUrl + '\'' +", goodsTag='" + goodsTag + '\'' +", amount=" + amount +", payer=" + payer +", detail=" + detail +", sceneInfo=" + sceneInfo +", settleInfo=" + settleInfo +'}';}public static WxJsApiRequest.Builder newBuilder() {return new WxJsApiRequest.Builder();}public static class Builder {private String appId;private String mchId;private String description;private String outTradeNo;private String timeExpire;private String attach;private String notifyUrl;private String goodsTag;private Integer total;private String currency;private JSONObject payer;private Integer costPrice;private List<String> goodsDetail;private JSONObject sceneInfo;private JSONObject settleInfo;private Builder() {}public WxJsApiRequest.Builder appId(String appId) {this.appId = appId;return this;}public WxJsApiRequest.Builder mchId(String mchId) {this.mchId = mchId;return this;}public WxJsApiRequest.Builder description(String description) {this.description = description;return this;}public WxJsApiRequest.Builder outTradeNo(String outTradeNo) {this.outTradeNo = outTradeNo;return this;}public WxJsApiRequest.Builder timeExpire(String timeExpire) {this.timeExpire = timeExpire;return this;}public WxJsApiRequest.Builder attach(String attach) {this.attach = attach;return this;}public WxJsApiRequest.Builder notifyUrl(String notifyUrl) {this.notifyUrl = notifyUrl;return this;}public WxJsApiRequest.Builder goodsTag(String goodsTag) {this.goodsTag = goodsTag;return this;}public WxJsApiRequest.Builder total(Integer total) {this.total = total;return this;}public WxJsApiRequest.Builder currency(String currency) {this.currency = currency;return this;}public WxJsApiRequest.Builder payer(JSONObject payer) {this.payer = payer;return this;}public WxJsApiRequest.Builder costPrice(Integer costPrice) {// todo: 成员变量的约束,比如 costPrice>0this.costPrice = costPrice;return this;}public WxJsApiRequest.Builder goodsDetail(List<String> goodsDetail) {this.goodsDetail = goodsDetail;return this;}public WxJsApiRequest.Builder sceneInfo(JSONObject sceneInfo) {this.sceneInfo = sceneInfo;return this;}public WxJsApiRequest.Builder settleInfo(JSONObject settleInfo) {this.settleInfo = settleInfo;return this;}public WxJsApiRequest build() {// todo: 成员变量之间的约束条件, 比如 total > costPricereturn new WxJsApiRequest(this);}}@Getterprivate static class WxAmount {private Integer total;private String currency;private WxAmount(Builder builder) {this.total = builder.total;this.currency = builder.currency;}}@Getterprivate class WxDetail {private Integer costPrice;private List<String> goodsDetail;private WxDetail(Builder builder) {this.costPrice = builder.costPrice;this.goodsDetail = builder.goodsDetail;}}}
具体调用处理
@RequestMapping(value = "test", method = RequestMethod.GET)public WxJsApiRequest test() {WxPayConfig instance = WxPayConfig.getInstance();WxPayParamConf wxPayParamConf = instance.getWxPayParamConf();System.out.println(JSON.toJSONString(wxPayParamConf));List<String> goodsDetail = new ArrayList<>();goodsDetail.add("test1");goodsDetail.add("test2");JSONObject payer = new JSONObject();payer.put("openid", "oa6sh5Q_tRltHkl11CJE-MF4GZ64");WxJsApiRequest wxJsApiRequest = WxJsApiRequest.newBuilder().appId("wxe97be9fe6f5b66cb").mchId("1421036202").description("测试商品").outTradeNo("P1234546").timeExpire("2021-06-16 16:55:00").notifyUrl("http://qa.weimi24.com/wxReceiver").total(2) // amout相关-总金额.currency("CNY") // amount相关-货币类型.payer(payer).costPrice(1).goodsDetail(goodsDetail).build();System.out.println(JSON.toJSONString(wxJsApiRequest));System.out.println(wxJsApiRequest.toString());return wxJsApiRequest;}
