NOTE

6.7 构建者模式

用于构建一个对象,这个对象由许多小对象组成,且流程复杂.如各种Builder. builder负责构建,director负责组装 1. uml 2. Java 2.1. client 2.2. 产品 2.3. 构造者 2.4. 装配者 3. Golang 3.1. client 3.2. 产品 3.

Software Architecture & Engineering创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

用于构建一个对象,这个对象由许多小对象组成,且流程复杂.如各种Builder. builder负责构建,director负责组装

1. uml

PlantUML 图表

2. Java

2.1. client

public class Client
{
    public static void main(String[] args)
    {
        AirShip ship = new MyAirshipDirector().direct(new MyAirshipBuilder());
        System.out.println(ship);
    }
}

2.2. 产品

public class AirShip
{
    private Engine engine;
    private EscapeTower tower;

    public Engine getEngine()
    {
        return engine;
    }

    public void setEngine(Engine engine)
    {
        this.engine = engine;
    }

    public EscapeTower getTower()
    {
        return tower;
    }

    public void setTower(EscapeTower tower)
    {
        this.tower = tower;
    }

    @Override
    public String toString()
    {
        return "AirShip{" + "engine=" + engine + ", tower=" + tower + '}';
    }
}
public class Engine
{
    private String name;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return "Engine{" + "name='" + name + '\'' + '}';
    }
}
public class EscapeTower
{
    private String name;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return "EscapeTower{" + "name='" + name + '\'' + '}';
    }
}

2.3. 构造者

public interface AirshipBuilder
{
    Engine buildEngine();
    EscapeTower buildTower();
}
public class MyAirshipBuilder implements AirshipBuilder
{
    @Override
    public Engine buildEngine()
    {
        Engine engine = new Engine();
        engine.setName("我的引擎");
        return engine;
    }

    @Override
    public EscapeTower buildTower()
    {
        EscapeTower escapeTower = new EscapeTower();
        escapeTower.setName("我的逃生塔");
        return escapeTower;
    }
}

2.4. 装配者

public interface AirshipDirector
{
    AirShip direct(AirshipBuilder airshipBuilder);
}
public class MyAirshipDirector implements AirshipDirector
{
    @Override
    public AirShip direct(AirshipBuilder airshipBuilder)
    {
        //通过builder构造组件
        Engine engine = airshipBuilder.buildEngine();
        EscapeTower escapeTower = airshipBuilder.buildTower();

        //这里可以和工厂模式结合
        AirShip airShip = new AirShip();

        //装配
        airShip.setEngine(engine);
        airShip.setTower(escapeTower);

        return airShip;
    }
}

3. Golang

3.1. client

func main() {
	fmt.Println(构建者.NewAirShipDirectorImpl().DirectAirShip(构建者.NewStrongAirShipPartsBuilder()).ToString())
	fmt.Println(构建者.NewAirShipDirectorImpl().DirectAirShip(构建者.NewWeakAirShipPartsBuilder()).ToString())
}

3.2. 产品

/*宇宙飞船的零件1:引擎*/
type Engine struct {
	Name string
}

func NewEngine(name string) *Engine {
	return &Engine{Name: name}
}

/*宇宙飞船的零件2:逃生塔*/
type EscapeTower struct {
	Name string
}

func NewEscapeTower(name string) *EscapeTower {
	return &EscapeTower{Name: name}
}

/*宇宙飞船*/
type AirShip struct {
	Engine      *Engine
	EscapeTower *EscapeTower
}

func NewAirShip(engine *Engine, escapeTower *EscapeTower) *AirShip {
	return &AirShip{Engine: engine, EscapeTower: escapeTower}
}

func (a AirShip) ToString() string {
	return "引擎: " + a.Engine.Name + " 逃生塔: " +  a.EscapeTower.Name
}

3.3. 构造者

/*宇宙飞船零件的构建者*/
type AirShipPartsBuilder interface {
	BuildEngine() *Engine
	BuildEscapeTower() *EscapeTower
}

type StrongAirShipPartsBuilder struct {
}

func NewStrongAirShipPartsBuilder() *StrongAirShipPartsBuilder {
	return &StrongAirShipPartsBuilder{}
}

func (s StrongAirShipPartsBuilder) BuildEngine() *Engine {
	return NewEngine("强悍的引擎")
}

func (s StrongAirShipPartsBuilder) BuildEscapeTower() *EscapeTower {
	return NewEscapeTower("强悍的逃生塔")

}


type WeakAirShipPartsBuilder struct {
}

func NewWeakAirShipPartsBuilder() *WeakAirShipPartsBuilder {
	return &WeakAirShipPartsBuilder{}
}

func (s WeakAirShipPartsBuilder) BuildEngine() *Engine {
	return NewEngine("弱逼的引擎")
}

func (s WeakAirShipPartsBuilder) BuildEscapeTower() *EscapeTower {
	return NewEscapeTower("弱逼的逃生塔")

}

3.4. 装配者

/*宇宙飞船零件的组装者*/
type AirShipDirector interface {
	DirectAirShip(AirShipPartsBuilder) AirShip
}

type AirShipDirectorImpl struct {
}

func NewAirShipDirectorImpl() *AirShipDirectorImpl {
	return &AirShipDirectorImpl{}
}

func (a AirShipDirectorImpl) DirectAirShip(builder AirShipPartsBuilder) *AirShip {
	return NewAirShip(builder.BuildEngine(), builder.BuildEscapeTower())
}

4. 实例

4.1. HttpBuilder

package builder

import (
	"bytes"
	"context"
	"net/http"
	"time"
)

// DefaultTimeout ...
const DefaultTimeout = 1

// HttpBuilder ...
type HttpBuilder struct {
	method      string
	url         string
	headers     map[string]string
	queryParams map[string]string
	body        string
	timeout     int
}

// NewHttpBuilder ...
func NewHttpBuilder() *HttpBuilder {
	return &HttpBuilder{
		headers:     make(map[string]string),
		queryParams: make(map[string]string),
	}
}

// Method ...
func (h *HttpBuilder) Method(method string) *HttpBuilder {
	h.method = method
	return h
}

// Url ...
func (h *HttpBuilder) Url(url string) *HttpBuilder {
	h.url = url
	return h
}

// Header ...
func (h *HttpBuilder) Header(key string, value string) *HttpBuilder {
	h.headers[key] = value
	return h
}

// QueryParam ...
func (h *HttpBuilder) QueryParam(key string, value string) *HttpBuilder {
	h.queryParams[key] = value
	return h
}

// Body ...
func (h *HttpBuilder) Body(body string) *HttpBuilder {
	h.body = body
	return h
}

// Timeout ...
func (h *HttpBuilder) Timeout(timeout int) *HttpBuilder {
	h.timeout = timeout
	return h
}

// 构造http client并且请求目标地址
// error不为nil时返回的resposne、CancelFunc在使用完毕后记得用defer释放资源
func (h *HttpBuilder) DoRequest() (*http.Response, context.CancelFunc, error) {
	req, err := http.NewRequest(h.method, h.url,
		bytes.NewBuffer([]byte(h.body)))
	if err != nil {
		return nil, nil, err
	}

	// 组装header
	for k, v := range h.headers {
		req.Header.Set(k, v)
	}

	// 组装query params
	query := req.URL.Query()
	for k, v := range h.queryParams {
		query.Add(k, v)
	}
	req.URL.RawQuery = query.Encode()

	// 设置timeout
	timeout := DefaultTimeout
	if h.timeout > 0 {
		timeout = h.timeout
	}
	ctx, cancel := context.WithTimeout(context.Background(),
		time.Duration(timeout)*time.Second)
	req = req.WithContext(ctx)

	// 构造client发起请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		defer cancel()
		return nil, nil, err
	}

	return resp, cancel, nil
}
  • 使用
response, cancelFunc, err := builder.NewHttpBuilder().
	Method(http.MethodGet).
	Url(config.GlobalTencentCloudConfig.TencentCloud.AccessToken.Url).
	QueryParam(constant.ParamAppId, appId).
	QueryParam(constant.ParamSecret, secret).
	QueryParam(constant.ParamGrantType,
		config.GlobalTencentCloudConfig.TencentCloud.AccessToken.GrantType).
	QueryParam(constant.ParamVersion,
		config.GlobalTencentCloudConfig.TencentCloud.Version).
	DoRequest()

if err != nil {
	metrics.Counter(constant.MonitorGetAccessTokenNetworkFail).Incr()

	log.ErrorContextf(ctx,
		"getAccessToken: call tencent cloud get token network err. err=%v",
		err.Error())
	return "", errs.New(trpc_utils.TransferRpcErr,
		fmt.Sprintf(constant.FuncErrorPrefix, trpc_utils.RunFuncName(),
			err))
}
defer cancelFunc()
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)

4.2. UrlBuilder

func BuildUrl(ctx context.Context, path string,
	params map[string]string) string {
	urlParams := url.Values{}
	for k, v := range params {
		urlParams.Set(k, v)
	}
	return fmt.Sprintf("%s?%s", path, urlParams.Encode())
}