GoLang 設計模型 — Decorator Pattern

地域列車車長 - James
5 min readAug 16, 2023

--

中文為裝飾者模式(Decorator Pattern),是指在不改變現有物件的結構下,動態地增加一些職責外的功能或是驗證。可以想像該模式會長得像同心圓,當使用者使用該物件時,需要經過一層一層驗證方可觸碰到最內部的物件核心。

此模式中的角色有:

  • 元件(Component):是個介面,其中會定義 Decorator們該執行些什麼方法。
  • 裝飾器(Decorator):會實作Component 中定義好的方法,並給具體上該裝飾器本身職責該做的事情。

使用場景

  • 如果開發者不想要再更動既有的物件情況下,想針對他新增些新功能或是驗證即可使用此模型。
  • 如果透過繼承來擴展物件行為的方案難以呈現,即可使用此模型。
  • Decorator 可以將商務邏輯依照層次結構進行分類,使用者可以透過介面去實作 Decorator 行為,且不同的Decorator可以相互組合。

Code 演練

其中我們定義了兩個 Decorator A & B,我們各自在 Decorator裡實作了 Operation並透過 SetComponent 來定義好 Decorator順序。

  • 專案架構
  • Component
package Components

import "fmt"

type Component interface {
Operation()
}

type ConcreteComponent struct {
}

func (c *ConcreteComponent) Operation() {
fmt.Println("ConcreteComponent operating")
}
  • Decorator-A
package decorators

import (
"decorator/Components"
"fmt"
)

type DecoratorA struct {
component Components.Component
}

func (da *DecoratorA) SetComponent(com Components.Component) {
da.component = com
}

func (da *DecoratorA) Operation() {
da.component.Operation()
da.InpendentMethod()
}

func (da *DecoratorA) InpendentMethod() {
fmt.Println("Inpendent Method of Decorator A")
}
  • Decorator-B
package decorators

import (
"decorator/Components"
"fmt"
)

type DecoratorB struct {
component Components.Component
}

func (db *DecoratorB) SetComponent(component Components.Component) {
db.component = component
}

func (db *DecoratorB) Operation() {
db.component.Operation()
fmt.Println(db.String())
}

func (db *DecoratorB) String() string {
return "Independent method of DecoratorB"
}
  • main.go
package main

import (
"decorator/Components"
decorators "decorator/Decorators"
)

func main() {

concreteComponent := Components.ConcreteComponent{}

decoratorA := decorators.DecoratorA{}
decoratorB := decorators.DecoratorB{}

// every decorator implements Component interface
decoratorA.SetComponent(&concreteComponent)
decoratorB.SetComponent(&decoratorA)
decoratorB.Operation()

}
  • 輸出效果
output would look like this

優缺點比較

優點

  • 為了擴展功能提出了一個靈活擴展的方案
  • 允許在運行時進行修該,而非直接修改原有程式碼
  • 支持 OCP (Opened-Closed-Principle)

缺點

  • 會建立出許多小物件,過度使用會導致專案架構複雜
  • 使用端嚴重依賴Componet的具體實現類型
  • 讓裝飾器跟蹤其他裝飾器,可能會很複雜

--

--