【博客388】设计模式之:建造者模式

内容:记录建造者模式的学习

建造者模式:

在程序设计中,我们会经常遇到一些复杂的对象,其中有很多成员属性,甚至嵌套着多个复杂的对象。
这种情况下,创建这个复杂对象就会变得很繁琐。


对于C++/而言,表现就是构造函数参数列表极长:
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、对多个对象复用同样的对象创建逻辑。

对复杂对象的构造,不使用建造者模式时的示例:

考虑如下的一个Message结构体,其主要有Header和Body组成:

package msg
...
type Message struct {
	Header *Header
	Body   *Body
}
type Header struct {
	SrcAddr  string
	SrcPort  uint64
	DestAddr string
	DestPort uint64
	Items    map[string]string
}
type Body struct {
	Items []string
}
...

//直接创建对象:
message := msg.Message{
	Header: &msg.Header{
		SrcAddr:  "192.168.0.1",
		SrcPort:  1234,
		DestAddr: "192.168.0.2",
		DestPort: 8080,
		Items:    make(map[string]string),
	},
	Body:   &msg.Body{
		Items: make([]string, 0),
	},
}

// 此时你需要知道对象的实现细节
message.Header.Items["contents"] = "application/json"
message.Body.Items = append(message.Body.Items, "record1")
message.Body.Items = append(message.Body.Items, "record2")

从其创建的代码来看,存在对对象使用者不友好和代码可读性差的缺点

对复杂对象的构造,使用建造者模式时的示例:

package msg
...
// Message对象的Builder对象
type builder struct {
	once *sync.Once
	msg *Message
}
// 返回Builder对象
func Builder() *builder {
	return &builder{
		once: &sync.Once{},
		msg: &Message{Header: &Header{}, Body: &Body{}},
	}
}
// 以下是对Message成员对构建方法
func (b *builder) WithSrcAddr(srcAddr string) *builder {
	b.msg.Header.SrcAddr = srcAddr
	return b
}
func (b *builder) WithSrcPort(srcPort uint64) *builder {
	b.msg.Header.SrcPort = srcPort
	return b
}
func (b *builder) WithDestAddr(destAddr string) *builder {
	b.msg.Header.DestAddr = destAddr
	return b
}
func (b *builder) WithDestPort(destPort uint64) *builder {
	b.msg.Header.DestPort = destPort
	return b
}
func (b *builder) WithHeaderItem(key, value string) *builder {
  // 保证map只初始化一次
	b.once.Do(func() {
		b.msg.Header.Items = make(map[string]string)
	})
	b.msg.Header.Items[key] = value
	return b
}
func (b *builder) WithBodyItem(record string) *builder {
	b.msg.Body.Items = append(b.msg.Body.Items, record)
	return b
}
// 创建Message对象,在最后一步调用
func (b *builder) Build() *Message {
	return b.msg
}


//测试代码如下:

package test
...
func TestMessageBuilder(t *testing.T) {
  // 使用消息建造者进行对象创建
	message := msg.Builder().
		WithSrcAddr("192.168.0.1").
		WithSrcPort(1234).
		WithDestAddr("192.168.0.2").
		WithDestPort(8080).
		WithHeaderItem("contents", "application/json").
		WithBodyItem("record1").
		WithBodyItem("record2").
		Build()
}

使用建造者模式来进行对象创建,使用者不再需要知道对象具体的实现细节,代码可读性也更好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值