三、建造者模式

news/2024/11/13 5:32:38/

构造者模式(Builder Pattern)使用简单的对象一步一步构建成一个复杂的对象。这种设计模式属于创建者模式,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。例如,计算机是由 CPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。

主要组成部分:

  1. 产品(Product)

    • 需要构建的复杂对象,通常是一个包含多个属性的类。
  2. 构造器接口(Builder)

    • 定义了构建产品的接口,通常包括设置产品各个部分的方法。
  3. 具体构建者(Concrete Builder)

    • 实现了构造器接口,负责具体产品的构建过程。通常还提供一个方法用于获取最终产品。
  4. 指挥者(Director)

    • 负责管理构建过程,调用构建者的具体方法来构建产品。
GO: 

其实在 Golang 中对于创建类参数比较多的对象的时候,我们常见的做法是必填参数直接传递,可选参数通过传递可变的方法进行创建。

方式一:使用 Go 编写建造者模式的代码其实会很长,这些是它的一个缺点,所以如果不是参数的校验逻辑很复杂的情况下一般我们在 Go 中不会采用这种方式,而会采用后面的另外一种方式
package builderimport "fmt"const (defaultMaxTotal = 10defaultMaxIdle  = 9defaultMinIdle  = 1
)// ResourcePoolConfig resource pool
type ResourcePoolConfig struct {name     stringmaxTotal intmaxIdle  intminIdle  int
}// ResourcePoolConfigBuilder 用于构建 ResourcePoolConfig
type ResourcePoolConfigBuilder struct {name     stringmaxTotal intmaxIdle  intminIdle  int
}// SetName SetName
func (b *ResourcePoolConfigBuilder) SetName(name string) error {if name == "" {return fmt.Errorf("name can not be empty")}b.name = namereturn nil
}// SetMinIdle SetMinIdle
func (b *ResourcePoolConfigBuilder) SetMinIdle(minIdle int) error {if minIdle < 0 {return fmt.Errorf("max tatal cannot < 0, input: %d", minIdle)}b.minIdle = minIdlereturn nil
}// SetMaxIdle SetMaxIdle
func (b *ResourcePoolConfigBuilder) SetMaxIdle(maxIdle int) error {if maxIdle < 0 {return fmt.Errorf("max tatal cannot < 0, input: %d", maxIdle)}b.maxIdle = maxIdlereturn nil
}// SetMaxTotal SetMaxTotal
func (b *ResourcePoolConfigBuilder) SetMaxTotal(maxTotal int) error {if maxTotal <= 0 {return fmt.Errorf("max tatal cannot <= 0, input: %d", maxTotal)}b.maxTotal = maxTotalreturn nil
}// Build Build
func (b *ResourcePoolConfigBuilder) Build() (*ResourcePoolConfig, error) {if b.name == "" {return nil, fmt.Errorf("name can not be empty")}// 设置默认值if b.minIdle == 0 {b.minIdle = defaultMinIdle}if b.maxIdle == 0 {b.maxIdle = defaultMaxIdle}if b.maxTotal == 0 {b.maxTotal = defaultMaxTotal}if b.maxTotal < b.maxIdle {return nil, fmt.Errorf("max total(%d) cannot < max idle(%d)", b.maxTotal, b.maxIdle)}if b.minIdle > b.maxIdle {return nil, fmt.Errorf("max idle(%d) cannot < min idle(%d)", b.maxIdle, b.minIdle)}return &ResourcePoolConfig{name:     b.name,maxTotal: b.maxTotal,maxIdle:  b.maxIdle,minIdle:  b.minIdle,}, nil
}
func TestBuilder(t *testing.T) {tests := []struct {name    stringbuilder *ResourcePoolConfigBuilderwant    *ResourcePoolConfigwantErr bool}{{name: "name empty",builder: &ResourcePoolConfigBuilder{name:     "",maxTotal: 0,},want:    nil,wantErr: true,},{name: "maxIdle < minIdle",builder: &ResourcePoolConfigBuilder{name:     "test",maxTotal: 0,maxIdle:  10,minIdle:  20,},want:    nil,wantErr: true,},{name: "success",builder: &ResourcePoolConfigBuilder{name: "test",},want: &ResourcePoolConfig{name:     "test",maxTotal: defaultMaxTotal,maxIdle:  defaultMaxIdle,minIdle:  defaultMinIdle,},wantErr: false,},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {got, err := tt.builder.Build()fmt.Printf("Build() error = %v, wantErr %v\n", err, tt.wantErr)fmt.Println(got)})}}

方式二:GO常用的参数传递方法 
package builderimport "fmt"const (defaultMaxTotal = 10defaultMaxIdle  = 9defaultMinIdle  = 1
)// ResourcePoolConfig resource pool
type ResourcePoolConfig struct {name     stringmaxTotal intmaxIdle  intminIdle  int
}// ResourcePoolConfigOption resource pool
type ResourcePoolConfigOption struct {maxTotal intmaxIdle  intminIdle  int
}// ResourcePoolConfigOptFunc to set option
type ResourcePoolConfigOptFunc func(option *ResourcePoolConfigOption)// NewResourcePoolConfig NewResourcePoolConfig
func NewResourcePoolConfig(name string, opts ...ResourcePoolConfigOptFunc) (*ResourcePoolConfig, error) {if name == "" {return nil, fmt.Errorf("name can not be empty")}option := &ResourcePoolConfigOption{maxTotal: 10,maxIdle:  9,minIdle:  1,}for _, opt := range opts {opt(option)}if option.maxTotal < 0 || option.maxIdle < 0 || option.minIdle < 0 {return nil, fmt.Errorf("args err, option: %v", option)}if option.maxTotal < option.maxIdle || option.minIdle > option.maxIdle {return nil, fmt.Errorf("args err, option: %v", option)}return &ResourcePoolConfig{name:     name,maxTotal: option.maxTotal,maxIdle:  option.maxIdle,minIdle:  option.minIdle,}, nil
}
func TestBuilder(t *testing.T) {type args struct {name stringopts []ResourcePoolConfigOptFunc}tests := []struct {name    stringargs    argswant    *ResourcePoolConfigwantErr bool}{{name: "name empty",args: args{name: "",},want:    nil,wantErr: true,},{name: "success",args: args{name: "test",opts: []ResourcePoolConfigOptFunc{func(option *ResourcePoolConfigOption) {option.minIdle = 2},func(option *ResourcePoolConfigOption) {option.maxTotal = 100},},},want: &ResourcePoolConfig{name:     "test",maxTotal: 10,maxIdle:  9,minIdle:  2,},wantErr: false,},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {got, err := NewResourcePoolConfig(tt.args.name, tt.args.opts...)require.Equalf(t, tt.wantErr, err != nil, "error = %v, wantErr %v", err, tt.wantErr)assert.Equal(t, tt.want, got)})}
}

JAVA:

...未完待续


http://www.ppmy.cn/news/1518664.html

相关文章

scrapy学习笔记0828-下

1.爬取动态页面 我们遇见的大多数网站不大可能会是单纯的静态网站&#xff0c;实际中更常见的是JavaScript通过HTTP请求跟网站动态交互 获取数据&#xff08;AJAX&#xff09;&#xff0c;然后使用数据更新HTML页面。爬取此类动态网 页需要先执行页面中的JavaScript代码渲染页…

<Rust>egui学习之小部件(八):如何在窗口中添加滑动条slider部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第八篇博…

GEE案例——基于光谱混合分析(SMA)的归一化差异水分指数(NDWFI)的水体监测

简介 本研究旨在开发一种新型水指数,以提高利用卫星图像感知和监测 SW 的能力,同时避开大量取样和复杂建模等劳动密集型技术,从而改进大规模 SW 测绘。 具体目标如下 (a) 引入一种新的水体指数,该指数的明确设计目的是改进对次要水体和易变水体的提取,使其非常适合于大规…

刘海屏的优雅回归?华为Mate 70 Pro定义新美学

在智能手机的发展历程中&#xff0c;华为Mate系列一直是高端旗舰的代表。而今&#xff0c;华为Mate 70 Pro的神秘面纱终于揭开&#xff0c;其回归的刘海屏设计和独特的寰宇舷窗设计&#xff0c;再次将华为的设计理念推向了新的高度。 刘海屏的回归&#xff1a;经典与创新的融合…

C#——扩展方法

扩展方法 定义 扩展方法&#xff08;Extension Methods&#xff09;是C#中一种特殊的静态方法&#xff0c;它定义在一个静态类中&#xff0c;但是可以像实例方法一样被调用&#xff0c;使得代码更加简洁、易读。 设计目的 是为了给已有的类型添加新的行为&#xff0c;而不需要…

SQLite的安装和使用

一、官网链接下载安装包 点击跳转 步骤&#xff1a;点击安装这个红框的dll以及红框下面的tools &#xff08;如果有navicat可以免上面这个安装步骤&#xff0c;安装上面这个是为了能在命令行敲SQL而已&#xff09; 二、SQLite的特点 嵌入的&#xff08;无服务器的&#x…

HTTP和HTTPS的区别?哪一个更适合你的网站?

什么是 HTTP&#xff1f; HTTP&#xff08;超文本传输协议&#xff09;&#xff08;Hypertext Transfer Protocol&#xff09;它是一组允许网络浏览器与网络服务器&#xff08;托管网站的计算机&#xff09;进行通信的规则。 HTTP 使用请求-响应模型。 例如&#xff0c;当你…

#驱动开发

内核模块 字符设备驱动 中断、内核定时器 裸机开发和驱动开发的区别&#xff1f; 裸机开发 驱动开发&#xff08;基于内核&#xff09; 相同点 都能够控制硬件&#xff08;本质&#xff1a;操作寄存器&#xff09; 不同点 用C语言给对应的地址里面写值 按照一定的框架格式…