将一个产品的内部表象与产品的生成过程分隔开,可以使一个建造过程生成具有不同内部表象的产品对象。
适用场景
将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示意图时,可以应用建造者模式。
组成结构
Product
具体的产品,要去构建的复杂对象。
Builder
为构建一个复杂对象的各个部件指定的抽象接口
concretBuilder
具体的构建者,实现 Builder 接口,构建具体产品的各个部件。
Director
指挥者,构建一个使用 Builder 接口的对象。
示例
需要构造一个表示文档的类,文档包括 id,最近更新时间,标题,请求地址,请求参数,相应参数,请求报文示例,响应报文示例,状态码表,自定义文档内容,文档来源类型等属性。有两种场景,需要构建两种不同的文档
- 用户提供请求参数和响应参数,后台按照一定的格式,自动生成用户需要的API文档。
- 用户提供自定义文档内容,后台填充更新时间,标题等信息,直接保存文档。
用户入参格式
{
"inputParamList": [
{
"fieldName": "name",
"defaultValue": "",
"alias": "bucketName",
"description": "名称",
"type": "string",
"securityPolicy": "策略1",
"confidentialityLevel": "公开"
}
],
"outputParamList": [
{
"fieldName": "code",
"defaultValue": "",
"alias": "code",
"description": "状态",
"type": "number",
"securityPolicy": "策略1",
"confidentialityLevel": "公开"
}
],
"method": "PutBucket",
"name": "创建存储空间"
}
文档对象实体类
import lombok.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Document {
/**
* 文档更新时间
*/
private Date updateTime;
/**
* 文档标题
*/
private String title;
/**
* 文档id
*/
private String documentId;
/**
* 文档请求地址
*/
private List<Map<String, String>> reqAddress;
/**
* 请求参数
*/
private List<Object> reqParam;
/**
* 响应参数
*/
private List<Object> respParam;
/**
* 请求报文示例
*/
private Map<String, Object> reqSample;
/**
* 响应报文示例
*/
private Map<String, Object> respSample;
/**
* 状态码表
*/
private List<InterfaceStatusCodeTable> statusCodeTableList;
/**
* 自定义文档内容
*/
private String content;
/**
* 文档来源类型,1--api文档,后台生成;2--自定义文档,用户上传
*/
private String type;
}
建造者接口
public interface InterfaceDocumentBuild {
void buildUpdateTime();
void buildTitle();
void buildDocumentId();
void buildReqAddress();
void buildReqParam();
void buildRespParam();
void buildReqSample();
void buildRespSample();
void buildStatusCodeTableList();
void buildContent();
void buildType();
}
建造者接口实现
API文档实现
import java.util.*;
import java.util.stream.Collectors;
@NoArgsConstructor
public class APIDocumentBuilder implements InterfaceDocumentBuild{
private static final int SUCCESS_CODE = 1000;
private static final String SUCCESS_MSG = "请求成功";
private Document document;
private String title;
private List<Object> reqParam;
private List<Object> respParam;
private List<InterfaceStatusCodeTable> statusCodeTableList;
private String documentId;
public APIDocumentBuilder(String name, String method, List<Object> inputParam, List<Object> outputParam, List<InterfaceStatusCodeTable> statusCodeTableList, String documentId) {
this.document = new Document();
this.title = String.format("%s(%s)", name, method);
this.reqParam = inputParam;
this.respParam = outputParam;
this.statusCodeTableList = statusCodeTableList;
this.documentId = documentId;
}
public APIDocumentBuilder(AddInterfaceReq req, String documentId) {
this(req.getName(), req.getMethod(), req.getInputParam(), req.getOutputParam(), req.getStatusCodeTable(), documentId);
}
public Document build() {
return this.document;
}
@Override
public void buildUpdateTime() {
this.document.setUpdateTime(new Date());
}
@Override
public void buildTitle() {
this.document.setTitle(this.title);
}
@Override
public void buildDocumentId() {
this.document.setDocumentId(this.documentId);
}
@Override
public void buildReqAddress() {
this.document.setReqAddress(getReqAddressList());
}
@Override
public void buildReqParam() {
this.document.setReqParam(this.reqParam);
}
@Override
public void buildRespParam() {
this.document.setRespParam(this.respParam);
}
@Override
public void buildReqSample() {
this.document.setReqSample(getSample(this.reqParam));
}
@Override
public void buildRespSample() {
this.document.setRespSample(getSample(this.respParam));
}
@Override
public void buildStatusCodeTableList() {
this.document.setStatusCodeTableList(statusCodeTableList);
}
@Override
public void buildContent() {
}
@Override
public void buildType() {
this.document.setType(DocumentSourceTypeEnum.AUTO_GENERATE_API.getCode());
}
/**
* mock 环境请求地址
*
* @return
*/
private List<Map<String, String>> getReqAddressList() {
List<String> environmentList = Arrays.asList("预发环境", "线上环境");
return environmentList.stream().map(environment -> {
Map<String, String> addressMap = new HashMap<>();
addressMap.put("environment", environment);
addressMap.put("serverURL", InterfaceMsgGeneratorUtil.generateFakeLink());
addressMap.put("path", "/cloud/print/getTemplates");
return addressMap;
}).collect(Collectors.toList());
}
/**
* 根据接口参数拼接请求和响应报文示例
*
* @param paramList
* @return
*/
private Map<String, Object> getSample(List<Object> paramList) {
Map<String, Object> respSampleMap = new HashMap<>();
respSampleMap.put("code", SUCCESS_CODE);
respSampleMap.put("message", SUCCESS_MSG);
Map<String, Object> dataMap = new HashMap<>();
respSampleMap.put("data", dataMap);
parseParamsToSample(new JSONArray(paramList), dataMap);
return respSampleMap;
}
/**
* 递归解析接口参数拼接报文
*
* @param obj
* @param data
*/
private void parseParamsToSample(Object obj, Map<String, Object> data) {
if (obj instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) obj;
for (Object object: jsonArray) {
parseParamsToSample(object, data);
}
} else if (obj instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) obj;
String fileName = jsonObject.getString("fieldName");
if (jsonObject.containsKey("children")) {
Map<String, Object> childMap = new HashMap<>();
if (StringUtils.equals(InterfaceParamTypeEnum.ARRAY.getCode(), jsonObject.getString("type"))) {
List<Object> childList = new ArrayList<>();
childList.add(childMap);
data.put(fileName, childList);
} else {
data.put(fileName, childMap);
}
parseParamsToSample(jsonObject.getJSONArray("children"), childMap);
} else {
data.put(fileName, getMockValue(jsonObject.getString("type"), jsonObject.getString("description")));
}
}
}
/**
* 生成默认值策略
*
* @param code
* @param value
* @return
*/
private Object getMockValue(String code, String value) {
Random random = new Random();
switch (BaseEnum.getByCode(InterfaceParamTypeEnum.class, code)){
case NUMBER:
return random.nextInt(10);
case STRING:
return UUID.randomUUID().toString().substring(0, 10);
case BOOLEAN:
return random.nextBoolean();
default:
break;
}
return null;
}
}
自定义文档实现
import com.be.jewel.open.client.domain.interfaces.Document;
import com.be.jewel.open.client.domain.interfaces.enums.DocumentSourceTypeEnum;
import com.be.mesh.client.annotate.MPI;
import com.be.mesh.client.prsim.Sequence;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
public class UploadDocumentBuilder implements InterfaceDocumentBuild{
private Document document;
private String title;
private String content;
private String documentId;
@MPI
private Sequence sequence;
public UploadDocumentBuilder(String title, String content, String documentId) {
this.document = new Document();
this.title = title;
this.content = content;
this.documentId = documentId;
}
public UploadDocumentBuilder (String name, String method, String content, String documentId) {
this(String.format("%s(%s)", name, method), content, documentId);
}
public Document build() {
return this.document;
}
@Override
public void buildUpdateTime() {
this.document.setUpdateTime(new Date());
}
@Override
public void buildTitle() {
this.document.setTitle(this.title);
}
@Override
public void buildDocumentId() {
this.document.setDocumentId(this.documentId);
}
@Override
public void buildReqAddress() {
}
@Override
public void buildReqParam() {
}
@Override
public void buildRespParam() {
}
@Override
public void buildReqSample() {
}
@Override
public void buildRespSample() {
}
@Override
public void buildStatusCodeTableList() {
}
@Override
public void buildContent() {
this.document.setContent(this.content);
}
@Override
public void buildType() {
this.document.setType(DocumentSourceTypeEnum.UPLOAD_CUSTOM.getCode());
}
}
指挥者
public class DocumentDirector {
private final InterfaceDocumentBuild builder;
public DocumentDirector(InterfaceDocumentBuild builder) {
this.builder = builder;
}
/**
* 构建文档
*/
public void construct() {
this.builder.buildType();
this.builder.buildUpdateTime();
this.builder.buildTitle();
this.builder.buildDocumentId();
this.builder.buildReqAddress();
this.builder.buildReqParam();
this.builder.buildRespParam();
this.builder.buildReqSample();
this.builder.buildRespSample();
this.builder.buildStatusCodeTableList();
this.builder.buildContent();
}
}
构造示例
/**
* 格式化用户上传的自定义文档
*
* @param title
* @param content
* @return
*/
private Document formatUploadDocument(String title, String content) {
UploadDocumentBuilder builder = new UploadDocumentBuilder(title, content, sequence.next("Table"));
DocumentDirector director = new DocumentDirector(builder);
director.construct();
return builder.build();
}
/**
* 根据请求参数构造 API 文档
*
* @param req
* @return
*/
private Document generateAPIDocument(AddInterfaceReq req) {
APIDocumentBuilder builder = new APIDocumentBuilder(req, sequence.next("Table"));
DocumentDirector director = new DocumentDirector(builder);
director.construct();
return builder.build();
}