【实践GoF的23种设计模式(建造者模式)】休言女子非英物,夜夜龙泉壁上鸣。这篇文章主要讲述实践GoF的23种设计模式:建造者模式相关的知识,希望能为你提供帮助。
摘要:针对这种对象成员较多,创建对象逻辑较为繁琐的场景,非常适合使用建造者模式来进行优化。本文分享自华为云社区《??【Go实现】实践GoF的23种设计模式:建造者模式??》,作者: 元闰子。
简述在程序设计中,我们会经常遇到一些复杂的对象,其中有很多成员属性,甚至嵌套着多个复杂的对象。这种情况下,创建这个复杂对象就会变得很繁琐。对于 C++/java 而言,最常见的表现就是构造函数有着长长的参数列表:
MyObject obj = new MyObject(param1, param2, param3, param4, param5, param6, ...)
对于 Go 语言来说,最常见的表现就是多层的嵌套实例化:
obj := & MyObject
Field1: & Field1
Param1: & Param1
Val: 0,
,
Param2: & Param2
Val: 1,
,
...
,
Field2: & Field2
Param3: & Param3
Val: 2,
,
...
,
...
上述的对象创建方法有两个明显的缺点:(1)对使用者不友好,使用者在创建对象时需要知道的细节太多;(2)代码可读性很差。
针对这种对象成员较多,创建对象逻辑较为繁琐的场景,非常适合使用建造者模式来进行优化。
建造者模式的作用有如下几个:1、封装复杂对象的创建过程,使对象使用者不感知复杂的创建逻辑。
2、可以一步步按照顺序对成员进行赋值,或者创建嵌套对象,并最终完成目标对象的创建。
3、对多个对象复用同样的对象创建逻辑。
其中,第1和第2点比较常用,下面对建造者模式的实现也主要是针对这两点进行示例。
UML 结构
代码实现示例
在??简单的分布式应用系统??(示例代码工程)中,我们定义了服务注册中心,提供服务注册、去注册、更新、 发现等功能。要实现这些功能,服务注册中心就必须保存服务的信息,我们把这些信息放在了 ?
?ServiceProfile?
?
这个数据结构上,定义如下:// demo/service/registry/model/service_profile.go
// ServiceProfile 服务档案,其中服务ID唯一标识一个服务实例,一种服务类型可以有多个服务实例
type ServiceProfile struct
Idstring// 服务ID
TypeServiceType// 服务类型
StatusServiceStatus// 服务状态
Endpoint network.Endpoint // 服务Endpoint
Region*Region// 服务所属region
Priority int// 服务优先级,范围0~100,值越低,优先级越高
Loadint// 服务负载,负载越高表示服务处理的业务压力越大
// demo/service/registry/model/region.go
// Region 值对象,每个服务都唯一属于一个Region
type Region struct
Idstring
Namestring
Country string
// demo/network/endpoint.go
// Endpoint 值对象,其中ip和port属性为不可变,如果需要变更,需要整对象替换
type Endpoint struct
ipstring
port int
实现
如果按照直接实例化方式应该是这样的:
// 多层的嵌套实例化
profile := & ServiceProfile
Id:"service1",
Type:"order",
Status:Normal,
Endpoint: network.EndpointOf("192.168.0.1", 8080),
Region: & Region // 需要知道对象的实现细节
Id:"region1",
Name:"beijing",
Country: "China",
,
Priority: 1,
Load:100,
虽然
ServiceProfile
结构体嵌套的层次不多,但是从上述直接实例化的代码来看,确实存在对使用者不友好和代码可读性较差的缺点。比如,使用者必须先对
Endpoint
和
Region
进行实例化,这实际上是将
ServiceProfile
的实现细节暴露给使用者了。下面我们引入建造者模式对代码进行优化重构:
// demo/service/registry/model/service_profile.go
// 关键点1: 为ServiceProfile定义一个Builder对象
type serviceProfileBuild struct
// 关键点2: 将ServiceProfile作为Builder的成员属性
profile *ServiceProfile
// 关键点3: 定义构建ServiceProfile的方法
func (s *serviceProfileBuild) WithId(id string) *serviceProfileBuild
s.profile.Id = id
// 关键点4: 返回Builder接收者指针,支持链式调用
return s
func (s *serviceProfileBuild) WithType(serviceType ServiceType) *serviceProfileBuild
s.profile.Type = serviceType
return s
func (s *serviceProfileBuild) WithStatus(status ServiceStatus) *serviceProfileBuild
s.profile.Status = status
return s
func (s *serviceProfileBuild) WithEndpoint(ip string, port int) *serviceProfileBuild
s.profile.Endpoint = network.EndpointOf(ip, port)
return s
func (s *serviceProfileBuild) WithRegion(regionId, regionName, regionCountry) *serviceProfileBuild
s.profile.Region = & RegionId: regionId, Name: regionName, Country: regionCountry
return s
func (s *serviceProfileBuild) WithPriority(priority int) *serviceProfileBuild
s.profile.Priority = priority
return s
func (s *serviceProfileBuild) WithLoad(load int) *serviceProfileBuild
s.profile.Load = load
return s
// 关键点5: 定义Build方法,在链式调用的最后调用,返回构建好的ServiceProfile
func (s *serviceProfileBuild) Build() *ServiceProfile
return s.profile
// 关键点6: 定义一个实例化Builder对象的工厂方法
func NewServiceProfileBuilder() *serviceProfileBuild
return & serviceProfileBuildprofile: & ServiceProfile
实现建造者模式有 6 个关键点:
- 为?
?ServiceProfile?
? 定义一个 Builder 对象??serviceProfileBuild?
?,通常我们将它设计为包内可见,来限制客户端的滥用。 - 把需要构建的?
?ServiceProfile?
? 作为 Builder 对象??serviceProfileBuild?
? 的成员属性,用来存储构建过程中的状态。 - 为 Builder 对象?
?serviceProfileBuild?
? 定义用来构建??ServiceProfile?
? 的一系列方法,上述代码中我们使用了??WithXXX?
? 的风格。 - 在构建方法中返回 Builder 对象指针本身,也即接收者指针,用来支持链式调用,提升客户端代码的简洁性。
- 为 Builder 对象定义Build()方法,返回构建好的?
?ServiceProfile?
? 实例,在链式调用的最后调用。 - 定义一个实例化 Builder 对象的工厂方法?
推荐阅读
- 谷歌浏览器打开一个新页面时使用新的标签
- Sublime Text 全局搜索Ctrl+Shift+F快捷键不能用
- 会声会影x7 每次安装均会提示(已安装这个产品的另一个版本)
- Sublime 添加∕删除右键菜单.bat
- 开机启动流程
- 实战案例(Redis集群动态缩容)
- k8s service到pod映射在iptable中的规则细节
- JavaScript进阶必会的手写功能
- Selenium3自动化测试38单元测试Pytest