建造者模式

将一个产品的内部表象与产品的生成过程分隔开,可以使一个建造过程生成具有不同内部表象的产品对象。

适用场景

将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示意图时,可以应用建造者模式。

组成结构

Product

具体的产品,要去构建的复杂对象。

Builder

为构建一个复杂对象的各个部件指定的抽象接口

concretBuilder

具体的构建者,实现 Builder 接口,构建具体产品的各个部件。

Director

指挥者,构建一个使用 Builder 接口的对象。

示例

需要构造一个表示文档的类,文档包括 id,最近更新时间,标题,请求地址,请求参数,相应参数,请求报文示例,响应报文示例,状态码表,自定义文档内容,文档来源类型等属性。有两种场景,需要构建两种不同的文档

  1. 用户提供请求参数和响应参数,后台按照一定的格式,自动生成用户需要的API文档。
  2. 用户提供自定义文档内容,后台填充更新时间,标题等信息,直接保存文档。

用户入参格式

{
    "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();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值