GO设计模式——5、建造者模式(创建型)

目录

[建造者模式(Builder Pattern)](#建造者模式(Builder Pattern))

建造者模式的核心角色

优缺点

使用场景

注意事项

代码实现


建造者模式(Builder Pattern)

建造者模式(Builder Pattern)是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

建造者模式的核心角色

1、抽象建造者(Builder):是为创建一个Product对象的各个部件指定的抽象接口。

2、具体建造者(ConcreteBuilder):实现Builder接口,构造和装配各个部件。

3、指挥者(Director):是构建一个实用Builder接口的对象。一方面它隔离了客户与生产过程;另一方面它负责控制产品的生成过程。

4、产品角色(Product):具体的产品

优缺点

(1)优点:

  • 分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
  • 可以更好地控制构建过程,隐藏具体构建细节。
  • 代码复用性高,可以在不同的构建过程中重复使用相同的建造者。

(2)缺点:

  • 如果产品的属性较少,建造者模式可能会导致代码冗余。
  • 建造者模式增加了系统的类和对象数量。

使用场景

建造者模式在创建复杂对象时非常有用,特别是当对象的构建过程涉及多个步骤或参数时。它可以提供更好的灵活性和可维护性,同时使得代码更加清晰可读。

  • 需要生成的对象具有复杂的内部结构。
  • 需要生成的对象内部属性本身相互依赖

注意事项

与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

代码实现

Go 复制代码
package main

import (
    "errors"
    "fmt"
)

// Product内的参数
type ResourceParams struct {
    name     string
    maxTotal int64
    maxIdle  int64
    minIdle  int64
}

// Product接口
type ResourceProduct interface {
    show()
}

// 实际Product,有show函数
type RedisResourceProduct struct {
    resourceParams ResourceParams
}

// show成员函数,用于显示product的参数内容
func (p *RedisResourceProduct) show() {
    fmt.Printf("Product的数据为 %+v ", p.resourceParams)
}

// 资源类创建接口
type ResourceBuilder interface {
    setName(name string) ResourceBuilder
    setMaxTotal(maxTotal int64) ResourceBuilder
    setMaxIdle(maxIdle int64) ResourceBuilder
    setMinIdle(minIdle int64) ResourceBuilder
    getError() error
    build() (p ResourceProduct)
}

// 实际建造者
type RedisResourceBuilder struct {
    resourceParams ResourceParams
    err            error
}

// 设置名称
func (r *RedisResourceBuilder) setName(name string) ResourceBuilder {
    if name == "" {
       r.err = errors.New("name为空")
       return r
    }
    r.resourceParams.name = name
    fmt.Println("RedisResourceBuilder setName ", name)
    return r
}

// 设置maxTotal值,值不能小于0
func (r *RedisResourceBuilder) setMaxTotal(maxTotal int64) ResourceBuilder {
    if maxTotal <= 0 {
       r.err = errors.New("maxTotal小于0")
       return r
    }
    r.resourceParams.maxTotal = maxTotal
    fmt.Println("RedisResourceBuilder setMaxTotal ", maxTotal)
    return r
}

// 设置maxIdle值,值不能小于0
func (r *RedisResourceBuilder) setMaxIdle(maxIdle int64) ResourceBuilder {
    if maxIdle <= 0 {
       r.err = errors.New("maxIdle小于0")
       return r
    }
    r.resourceParams.maxIdle = maxIdle
    fmt.Println("RedisResourceBuilder setMaxIdle ", maxIdle)
    return r
}

// 设置minIdle值,值不能小于0
func (r *RedisResourceBuilder) setMinIdle(minIdle int64) ResourceBuilder {
    if minIdle <= 0 {
       r.err = errors.New("minIdle小于0")
       return r
    }
    r.resourceParams.minIdle = minIdle
    fmt.Println("RedisResourceBuilder setMinIdle ", minIdle)
    return r
}

// 获取错误信息
func (r *RedisResourceBuilder) getError() error {
    return r.err
}

// 构建product: 1. 做参数校验  2. 根据参数生成product
func (r *RedisResourceBuilder) build() (p ResourceProduct) {
    // 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
    if r.resourceParams.name == "" {
       r.err = errors.New("name为空")
       return
    }

    if !((r.resourceParams.maxIdle == 0 && r.resourceParams.minIdle == 0 && r.resourceParams.maxTotal == 0) ||
       (r.resourceParams.maxIdle != 0 && r.resourceParams.minIdle != 0 && r.resourceParams.maxTotal != 0)) {
       r.err = errors.New("数据需要保持一致")
       return
    }

    if r.resourceParams.maxIdle > r.resourceParams.maxTotal {
       r.err = errors.New("maxIdle > maxTotal")
       return
    }
    if r.resourceParams.minIdle > r.resourceParams.maxTotal || r.resourceParams.minIdle > r.resourceParams.maxIdle {
       r.err = errors.New("minIdle > maxTotal|maxIdle")
       return
    }
    fmt.Println("RedisResourceBuilder build")
    product := &RedisResourceProduct{
       resourceParams: r.resourceParams,
    }
    return product
}

// 指挥者
type Director struct {
}

// 指挥者控制建造过程
func (d *Director) construct(builder ResourceBuilder) ResourceProduct {
    resourceProduct := builder.setName("redis").
       setMinIdle(10).
       setMaxIdle(10).
       setMaxTotal(20).
       build()

    err := builder.getError()
    if err != nil {
       fmt.Println("构建失败,原因为" + err.Error())
       return nil
    }
    return resourceProduct
}

func main() {
    builder := &RedisResourceBuilder{}

    director := &Director{}
    product := director.construct(builder)

    if product == nil {
       return
    }

    product.show()
}
相关推荐
小白要加油哈18 分钟前
游戏开发--C#面试题
开发语言·笔记·学习·microsoft·unity·c#·游戏引擎
陈随易33 分钟前
wangEditor,从开源、停更到重生
前端·后端·程序员
gsgbgxp38 分钟前
C++类中的const成员变量和const成员函数
开发语言·c++·算法
亚洲第一中锋_哈达迪38 分钟前
漫谈分布式唯一ID
分布式·后端
唐僧洗头爱飘柔952741 分钟前
(Go语言)条件判断与循环?切片和数组的关系?映射表与Map?三组关系傻傻分不清?本文带你了解基本的复杂类型与执行判断语句
golang·go语言·go复杂类型·go条件判断·go循环·go映射表·go切片
皮克斯的进化之路1 小时前
RabbitMQ的死信队列
java·开发语言
小扳1 小时前
RabbitMQ 篇-深入了解延迟消息、MQ 可靠性(生产者可靠性、MQ 可靠性、消费者可靠性)
java·分布式·后端·spring·rabbitmq
唐僧洗头爱飘柔95271 小时前
(Go语言)初上手Go?本篇文章帮拿捏Go的数据类型!
开发语言·golang·go语言·go数据类型·go开发·go初上手
唐僧洗头爱飘柔95271 小时前
(Go基础)变量与常量?字面量与变量的较量!
开发语言·后端·golang·go·go语言初上手
·云扬·1 小时前
Lambda 表达式详解
java·开发语言·笔记·学习·1024程序员节