基本概念
简单描述
建造者模式是一种用来创建具有复杂类型的对象(比如汽车,需要各种零件组装构成—复杂)所使用的设计模式。可以设置不同的可选参数,定制化地创建不同的对象(比如:有天窗的汽车,能容纳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.newBuilder
1、静态内部类 Builder
2、构造方法 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)
*/
@Getter
public 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;
}
@Override
public 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>0
this.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 > costPrice
return new WxJsApiRequest(this);
}
}
@Getter
private static class WxAmount {
private Integer total;
private String currency;
private WxAmount(Builder builder) {
this.total = builder.total;
this.currency = builder.currency;
}
}
@Getter
private 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;
}