将建造物件的实作拆开,由使用者觉得要选择建造什麽,来一步一步建造
举例来说,当创建 PS5 时,
CreatePS5(hasCPU, hasGPU bool)
如果有许多额外的选项,
CreatePS5(CPUCores uint8, has大摇, has蓝牙耳机 bool)
就会发现额外的选项需透过零值(zero value)来解决,
CreatePS5(4, false, true)
这使得建构 PS5 的 function 难以快速理解其中的意义。
所以需要额外将这些步骤拆除,再由使用者决定是否要执行,并且将这些步骤拆分,也使得建构 function 不至於过长,
CreatePS5(4).
Set大摇(true).
// Set蓝牙耳机(true) 不执行就不会有蓝牙耳机
优点:
设计上通常有Product、Director、Builder Interface、ConcreteBuilder,
使用者购买 PS5,并且其中有多个周边可以购买,使用者自行决定要加购什麽周边
UML 图後如下:
程序码如下:
(相关的 code 在Github - go-design-patterns)
package main
import (
"fmt"
"strings"
)
type PS5Builder interface {
SetController(isBuy bool) PS5Builder
SetBluetoothHeadphones(isBuy bool) PS5Builder
Build() *PS5
}
type PS5 struct {
cpu string
gpu string
controller string
bluetoothHeadphones string
}
func CreatePS5() *PS5 {
return &PS5{
cpu: "cpu",
gpu: "gpu",
}
}
func (p PS5) PlayGame() {
var (
accessories []string
withAccessories string
)
if p.controller != "" {
accessories = append(accessories, p.controller)
}
if p.bluetoothHeadphones != "" {
accessories = append(accessories, p.bluetoothHeadphones)
}
if len(accessories) != 0 {
withAccessories = " with " + strings.Join(accessories, ", ")
}
fmt.Printf("loading...play%s!\n", withAccessories)
}
type PS5Director struct {
Builder PS5Builder
}
func CreatePS5Director(concretePS5Builder *ConcretePS5Builder) *PS5Director {
return &PS5Director{
Builder: concretePS5Builder,
}
}
func (p PS5Director) Construct() *PS5 {
return p.Builder.
SetController(true).
Build()
}
type ConcretePS5Builder struct {
ps5 *PS5
}
func CreateConcretePS5Builder() *ConcretePS5Builder {
return &ConcretePS5Builder{
ps5: CreatePS5(),
}
}
func (p *ConcretePS5Builder) SetController(isBuy bool) PS5Builder {
if isBuy {
p.ps5.controller = "FightingStick"
}
return p
}
func (p *ConcretePS5Builder) SetBluetoothHeadphones(isBuy bool) PS5Builder {
if isBuy {
p.ps5.bluetoothHeadphones = "BluetoothHeadphones"
}
return p
}
func (p *ConcretePS5Builder) Build() *PS5 {
return p.ps5
}
func main() {
concretePS5Builder := CreateConcretePS5Builder()
ps5Director := CreatePS5Director(concretePS5Builder)
ps5 := ps5Director.Construct()
ps5.PlayGame()
}
CreateConcretePS5Builder()
建立实际的 builder 後,丢入PS5Director{}
,而PS5Director{}
会在透过Construct()
来操作 builder 去 set ps5。
可以发现必填的栏位在CreateConcretePS5Builder()
就已经填好,如果是有建构子(construct)的语言,例如 java 就会在建构子内做好,由於 golang 没有,所以会用 create function 来达到此效果。而额外的栏位即在.SetXXX()
function 设置。
另外在.SetXXX()
function 後又会 return 自己的方式称为 Fluent interface,此方法可以做出链式的写法,即.SetXXX().SetXXX()
,可以让 set function 的使用更灵活。
>>: 【领域展开 15 式】 裸窥 WordPress Soledad 主题客制栏位
-计算机架构 作为解决方案最重要的工件,架构是一个对象(解决方案)从各种观点或角度的概念、逻辑和物...
今日要点 》前言 》介绍 Demo 专案 》程序架构研究 前言 前面精选了很多在 Github 上很...
前言 原本以为生命周期应该很好懂, 但我卡在别的地方, 不过快 12 点了啊我先 po 出我目前进度...
可以用 shioaji api 取得即时报价後,就有很多应用场景,这边先示范一个比较简单的,使用 L...
目标 学习如何抓取跟分析声音制作互动 了解如何抓取与绘制使用者的即时影片 学习如何把即时影像转成即时...