2017-08-29 106 views
3

Decorator模式(函數)具有many benefits裝飾功能轉到

這是非常有用的,當一個方法有許多正交關注......也就是說,這些問題都不是相關的,比我們想其他的做無論何時我們稱之爲我們的方法,所有(或部分)他們。這是裝飾模式真正幫助的地方。

通過實現裝飾者模式,我們訂閱開閉本。我們的方法對未來的擴展是開放的,但對未來的修改關閉。遵守開放原則有許多優點。

但是,我發現的所有例子都非常複雜(例如,用許多中間件編寫HTTP服務器)。這使我很難在其他地方應用該原則。我需要一些我可以輕鬆嘗試的東西,以便圍繞它環繞我的頭部。

有人可以給我一個更簡單的例子,可以最好地說明如何在Go中做Decorator模式(函數)嗎?

This example by Alex Alehano,太簡單,無法投入實際使用。我需要的東西,可以說明這一點:

func Decorate(c Decorated, ds ...Decorator) Decorated { 
    decorated := c 
    for _, decorate := range ds { 
     decorated = decorate(decorated) 
    } 
    return decorated 
} 

根據不同選項/指令,例如,以上,以較低的,爲Base64等,將是最好的示例IMO,並添加前綴/後綴甲字符串操作也作爲「This technique proves especially valuable if the decorators themselves are parameterized」。

回答

4

首先,一個修飾基本上是一個函數,它接受特定類型作爲其參數的另一個函數,並返回的相同的功能類型。這實質上允許您創建一系列功能。因此,在進入這將是這個樣子:

// this is the type of functions you want to decorate 
type StringManipulator func(string) string 

// this is your decorator. 
func ToLower(m StringManipulator) StringManipulator { 
    return func(s string) string { 
     lower := strings.ToLower(s) 
     return m(lower) 
    } 
} 

here's a more complete example

+0

這正是Go中的Decorator函數模式,我一直在尋找非常感謝! – xpt

+0

如果我理解正確,按照定義的'AppendDecorator',只能用作第一個操作追加? – RayfenWindspear

+0

https://play.golang.org/p/rrBnAJOIc2不,AppendDecorator與其他的有所不同,因爲你需要調用它來返回實際的裝飾器,而不是使用你想要的函數調用它裝飾。基本上它只是爲你傳遞給AppendDecorator的字符串創建一個閉包,並返回一個新的裝飾器,然後訪問該字符串... – mkopriva

2

我知道裝飾者/中間件的一個很好的例子,它利用了你演示的相同技巧。這是不特定的字符串操作,雖然,但我覺得很精美的,這(通過代碼掃描):

https://github.com/basvanbeek/pubsub/blob/master/kafka/publisher.go

看看在type PublisherOption func(*publisherConfig) error

你會發現,某些功能返回PublisherOption類型。這些是裝飾器/中間件。

行動發生在NewKafkaPublisher功能:

func NewKafkaPublisher(
    broker, topic string, 
    options ...PublisherOption, 
) (pubsub.Publisher, error) { 
    if len(strings.Trim(broker, " \t")) == 0 { 
     return nil, ErrNoBrokers 
    } 
    brokerHosts := strings.Split(broker, ",") 

    if len(topic) == 0 { 
     return nil, ErrNoTopic 
    } 
    // set sensible defaults 
    pc := &publisherConfig{ 
    syncPublisher: defaultSyncPublisher, 
    ackMode:  defaultRequiredAcks, 
    successes:  nil, 
    logger:  log.NewNopLogger(), 
    topic:   topic, 
    partitioner: sarama.NewManualPartitioner(topic), 
    partition:  0, 
    } 

// parse optional parameters 
for _, option := range options { 
    if err := option(pc); err != nil { 
     return nil, err 
    } 
} 

注意,它遍歷option,並呼籲各裝飾/中間件。

補充例是在這裏:https://gist.github.com/steven-ferrer/e4c1eb973a930c2205039448cda6d3d9

可運行代碼:https://play.golang.org/p/ZXixnyTHXH

希望的是,根據不同的選項/指令,例如,以幫助上:)

+0

的困難,我是在其他地方適用的原則。看看你引用的代碼不幸並不能讓我更好地理解它,以及如何應用它來解決我自己的問題。對我來說,圍繞它過於複雜。 – xpt

+0

我創建了一個簡單的示例,請參閱:https://gist.github.com/steven-ferrer/e4c1eb973a930c2205039448cda6d3d9 – srf

+0

感謝您的幫助。 Upvoated! – xpt

3

甲字符串處理,以降低,添加前綴/後綴,base64等,將是最好的例子國際海事組織。

這是你問的例子:

package main 

import (
    "fmt" 
    "strings" 
) 

const (
    prefix = "PREFIX" 
    suffix = "SUFFIX" 
) 

type Decorated=string 

func addConstPrefix(s string) string { 
    return prefix + s 
} 

func addConstSuffix(s string) string { 
    return s + suffix 
} 

type Decorator=func(string) string 

func Decorate(c Decorated, ds ...Decorator) Decorated { 
    decorated := c 
    for _, decorator := range ds { 
     decorated = decorator(decorated) 
    } 
    return decorated 
} 

func main() { 

    var toLower Decorator = strings.ToLower 
    var toUpper Decorator = strings.ToUpper 
    var dec3 Decorator = addConstPrefix 
    var dec4 Decorator = addConstSuffix 

    input := "Let's decorate me!" 
    inputUppercase := Decorate(input, []Decorator{toUpper}...) 
    fmt.Println(inputUppercase) 

    allDecorators := []Decorator{toUpper, toLower, dec3, dec4} 
    output := Decorate(input, allDecorators...) 
    fmt.Println(output) 
} 

注意,爲了簡單起見,使用Golang的類型別名,這是在圍棋1.9推出。這些都是我們所使用的兩個別名:

type Decorated=string 
type Decorator=func(string)string 

,這樣以後可應用於您的Decorate()功能。然後,我們只是創造一些裝飾相匹配,我們定義的類型簽名這(功能):

var toLower Decorator = strings.ToLower 
var toUpper Decorator = strings.ToUpper 
var dec3 Decorator = addConstPrefix 
var dec4 Decorator = addConstSuffix 

,並將其應用:

allDecorators := []Decorator{toUpper, toLower, dec3, dec4} 
output := Decorate(input, allDecorators...) 

編輯:

一個參數化裝飾會簡單地說就是返回另一個功能的功能,例如:

func addPrefix(prefix string) func(string) string { 
    return func(s string) string { 
     return prefix + s 
    } 
} 

它可以然後以下列方式施加:

input2 := "Let's decorate me!" 
prefixed := Decorate(input2, []Decorator{addPrefix("Well, ")}...) 
+0

哇,很好,不知道有類型別名:) – srf

+0

@srxf類型別名剛剛在上週發佈的Go 1.9中添加。 – Adrian

+0

真棒,得更新我的自我。謝謝@阿德里安! – srf