Golang 常見設計模式之選項模式
熟悉 Python 開發的同學都知道,Python 有預設引數的存在,使得我們在例項化一個物件的時候,可以根據需要來選擇性的覆蓋某些預設引數,以此來決定如何例項化物件。當一個物件有多個預設引數時,這個特性非常好用,能夠優雅地簡化程式碼。
而 Go 語言從語法上是不支援預設引數的,所以為了實現既能透過預設引數建立物件,又能透過傳遞自定義引數建立物件,我們就需要透過一些程式設計技巧來實現。對於這些程式開發中的常見問題,軟體行業的先行者們總結了許多解決常見場景編碼問題的最佳實踐,這些最佳實踐後來成為了我們所說的設計模式。其中選項模式在 Go 語言開發中會經常用到。
通常我們有以下三種方法來實現透過預設引數建立物件,以及透過傳遞自定義引數建立物件:
-
使用多個建構函式
-
預設引數選項
-
選項模式
透過多建構函式實現
第一種方式是透過多建構函式實現,下面是一個簡單例子:
package main
import "fmt"
const (
defaultAddr = "127.0.0.1"
defaultPort = 8000
)
type Server struct {
Addr string
Port int
}
func NewServer() * Server {
return & Server{
Addr: defaultAddr,
Port: defaultPort,
}
}
func NewServerWithOptions( addr string, port int) * Server {
return & Server{
Addr: addr,
Port: port,
}
}
func main() {
s1 : = NewServer()
s2 : = NewServerWithOptions( "localhost", 8001)
fmt. Println( s1) // &{127.0.0.1 8000}
fmt. Println( s2) // &{localhost 8001}
}
這裡我們為 Server 結構體實現了兩個建構函式:
-
NewServer:無需傳遞引數即可直接返回 Server 物件
-
NewServerWithOptions :需要傳遞 addr 和 port 兩個引數來構造 Server 物件
如果透過預設引數建立的物件即可滿足需求,不需要對 Server 進行定製時,我們可以使用 NewServer 來生成物件(s1)。而如果需要對 Server 進行定製時,我們則可以使用 NewServerWithOptions 來生成物件(s2)。
透過預設引數選項實現
另外一種實現預設引數的方案,是為要生成的結構體物件定義一個選項結構體,用來生成要建立物件的預設引數,程式碼實現如下:
package main
import "fmt"
const (
defaultAddr = "127.0.0.1"
defaultPort = 8000
)
type Server struct {
Addr string
Port int
}
type ServerOptions struct {
Addr string
Port int
}
func NewServerOptions() * ServerOptions {
return & ServerOptions{
Addr: defaultAddr,
Port: defaultPort,
}
}
func NewServerWithOptions( opts * ServerOptions) * Server {
return & Server{
Addr: opts. Addr,
Port: opts. Port,
}
}
func main() {
s1 : = NewServerWithOptions( NewServerOptions())
s2 : = NewServerWithOptions( & ServerOptions{
Addr: "localhost",
Port: 8001,
})
fmt. Println( s1) // &{127.0.0.1 8000}
fmt. Println( s2) // &{localhost 8001}
}
我們為 Server 結構體專門實現了一個 ServerOptions 用來生成預設引數,呼叫 NewServerOptions 函式即可獲得預設引數配置,建構函式 NewServerWithOptions 接收一個 *ServerOptions 型別作為引數。所以我們可以透過以下兩種方式來完成功能:
-
直接將呼叫 NewServerOptions 函式的返回值傳遞給 NewServerWithOptions 來實現透過預設引數生成物件(s1)
-
透過手動構造 ServerOptions 配置來生成定製物件(s2)
透過選項模式實現
以上兩種方式雖然都能夠完成功能,但卻有以下缺點:
-
透過多建構函式實現的方案需要我們在例項化物件時分別呼叫不同的建構函式,程式碼封裝性不強,會給呼叫者增加使用負擔。
-
透過預設引數選項實現的方案需要我們預先構造一個選項結構,當使用預設引數生成物件時程式碼看起來比較冗餘。
而選項模式可以讓我們更為優雅地解決這個問題。程式碼實現如下:
package main
import "fmt"
const (
defaultAddr = "127.0.0.1"
defaultPort = 8000
)
type Server struct {
Addr string
Port int
}
type ServerOptions struct {
Addr string
Port int
}
type ServerOption interface {
apply( * ServerOptions)
}
type FuncServerOption struct {
f func( * ServerOptions)
}
func ( fo FuncServerOption) apply( option * ServerOptions) {
fo. f( option)
}
func WithAddr( addr string) ServerOption {
return FuncServerOption{
f: func( options * ServerOptions) {
options. Addr = addr
},
}
}
func WithPort( port int) ServerOption {
return FuncServerOption{
f: func( options * ServerOptions) {
options. Port = port
},
}
}
func NewServer( opts ... ServerOption) * Server {
options : = ServerOptions{
Addr: defaultAddr,
Port: defaultPort,
}
for _, opt : = range opts {
opt. apply( & options)
}
return & Server{
Addr: options. Addr,
Port: options. Port,
}
}
func main() {
s1 : = NewServer()
s2 : = NewServer( WithAddr( "localhost"), WithPort( 8001))
s3 : = NewServer( WithPort( 8001))
fmt. Println( s1) // &{127.0.0.1 8000}
fmt. Println( s2) // &{localhost 8001}
fmt. Println( s3) // &{127.0.0.1 8001}
}
乍一看我們的程式碼複雜了很多,但其實呼叫建構函式生成物件的程式碼複雜度是沒有改變的,只是定義上的複雜。
我們定義了 ServerOptions 結構體用來配置預設引數。因為 Addr 和 Port 都有預設引數,所以 ServerOptions 的定義和 Server 定義是一樣的。但有一定複雜性的結構體中可能會有些引數沒有預設引數,必須讓使用者來配置,這時 ServerOptions 的欄位就會少一些,大家可以按需定義。
同時,我們還定義了一個 ServerOption 介面和實現了此介面的 FuncServerOption 結構體,它們的作用是讓我們能夠透過 apply 方法為 ServerOptions 結構體單獨配置某項引數。
我們可以分別為每個預設引數都定義一個 WithXXX 函式用來配置引數,如這裡定義的 WithAddr 和 WithPort ,這樣使用者就可以透過呼叫 WithXXX 函式來定製需要覆蓋的預設引數。
總結
透過 s2 和 s3 的列印結果可以發現,使用選項模式實現的建構函式更加靈活,相較於前兩種實現,選項模式中我們可以自由的更改其中任意一項或多項預設配置。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70021806/viewspace-2913968/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- golang 設計模式之選項模式Golang設計模式
- Golang 常見設計模式之裝飾模式Golang設計模式
- Golang 常見設計模式之單例模式Golang設計模式單例
- 常見的Golang設計模式實現?Golang設計模式
- golang設計模式之單例模式Golang設計模式單例
- golang設計模式之迭代器模式Golang設計模式
- golang設計模式之建造者模式Golang設計模式
- golang設計模式之原型模式Golang設計模式原型
- JavaScript 常見設計模式JavaScript設計模式
- golang設計模式之工廠方法模式Golang設計模式
- golang設計模式之觀察者模式Golang設計模式
- golang設計模式之抽象工廠模式Golang設計模式抽象
- golang中的選項模式Golang模式
- js常見的設計模式JS設計模式
- Golang常見的併發模式Golang模式
- golang設計模式之簡單工廠模式Golang設計模式
- JavaScript—常見設計模式整理(27)JavaScript設計模式
- 前端常見設計模式彙總前端設計模式
- GoLang設計模式08 - 命令模式Golang設計模式
- GoLang設計模式15 - 策略模式Golang設計模式
- Java常見知識點彙總(⑩)——常見設計模式Java設計模式
- GoLang設計模式20 - 組合模式Golang設計模式
- GoLang設計模式17 - 訪客模式Golang設計模式
- GoLang設計模式19 - 橋接模式Golang設計模式橋接
- GoLang設計模式01 - 建造者模式Golang設計模式
- GoLang設計模式02 - 工廠模式Golang設計模式
- GoLang設計模式04 - 單例模式Golang設計模式單例
- GoLang設計模式05 - 原型模式Golang設計模式原型
- GoLang設計模式06 - 物件池模式Golang設計模式物件
- GoLang設計模式14 - 狀態模式Golang設計模式
- GoLang設計模式12 - 空物件模式Golang設計模式物件
- GoLang設計模式21 - 裝飾模式Golang設計模式
- 圖解九種常見的設計模式圖解設計模式
- Python設計模式有哪些?常見分類!Python設計模式
- GoLang設計模式11 - 備忘錄模式Golang設計模式
- GoLang設計模式13 - 觀察者模式Golang設計模式
- 設計模式之策略模式設計模式
- 設計模式之代理模式設計模式