架構(gòu)模式叹放,可以使你的代碼可復(fù)用性高,代碼整潔挠羔,如果不用架構(gòu)模式寫(xiě)出來(lái)的代碼就是字符的堆砌许昨,沒(méi)有美感。
掌握了golang的基礎(chǔ)之后褥赊,就應(yīng)該在之后的代碼中以架構(gòu)模式的方式去編程。
第一種架構(gòu)模式 pipe-filter莉恼。
pipe-filter
- 其架構(gòu)適用于 解析拌喉,過(guò)濾,處理俐银,返回這樣的架構(gòu)尿背,如數(shù)據(jù)分析。
- filter 用于數(shù)據(jù)的過(guò)濾捶惜。而pipe 用于連接filter傳遞數(shù)據(jù)田藐,或者異步處理緩沖數(shù)據(jù)流。
-
松耦合:filter 只和數(shù)據(jù)耦合吱七。
pipe-filter
下面的例子是一個(gè)將 字符串“1汽久,2,3” 按逗號(hào)切分后踊餐,再字符轉(zhuǎn)數(shù)字相加的過(guò)程景醇。
pipe-filter
1、首先實(shí)現(xiàn)一個(gè) filter 的接口吝岭。該接口定義了數(shù)據(jù)的來(lái)源接口三痰,輸出接口,該filter接口必須擁有的處理方法
filter.go
package pipe_filter
// Request is the input of the filter
type Request interface{}
// Response is the output of the filter
type Response interface{}
// Filter interface is the definition of the data processing components
// Pipe-Filter structure
type Filter interface {
Process(data Request) (Response, error)
}
2窜管、定義需要的filter散劫,在這里filter的工作順序是串行的,首先是按“幕帆,”拆分获搏,其次將字符型轉(zhuǎn)換為數(shù)字形。最后加起來(lái)蜓肆。每個(gè)filter都必須實(shí)現(xiàn)一個(gè)Process方法颜凯,因?yàn)橹皇窃趂ilter.go 里定義好的谋币。
split_filter.go (拆分)
package pipe_filter
import (
"errors"
"strings"
)
var SplitFilterWrongFormatError = errors.New("input data should be string")
type SplitFilter struct {
delimiter string
}
func NewSplitFilter(delimiter string) *SplitFilter {
return &SplitFilter{delimiter}
}
func (sf *SplitFilter) Process(data Request) (Response, error) {
str, ok := data.(string) //檢查數(shù)據(jù)格式/類型,是否可以處理
if !ok {
return nil, SplitFilterWrongFormatError
}
parts := strings.Split(str, sf.delimiter)
return parts, nil
}
toint_filter.go (字符轉(zhuǎn)整數(shù))
package pipe_filter
import (
"errors"
"strconv"
)
var ToIntFilterWrongFormatError = errors.New("input data should be []string")
type ToIntFilter struct {
}
func NewToIntFilter() *ToIntFilter {
return &ToIntFilter{}
}
func (tif *ToIntFilter) Process(data Request) (Response, error) {
parts, ok := data.([]string)
if !ok {
return nil, ToIntFilterWrongFormatError
}
ret := []int{}
for _, part := range parts {
s, err := strconv.Atoi(part)
if err != nil {
return nil, err
}
ret = append(ret, s)
}
return ret, nil
}
sum_filter.go (累加)
package pipe_filter
import "errors"
var SumFilterWrongFormatError = errors.New("input data should be []int")
type SumFilter struct {
}
func NewSumFilter() *SumFilter {
return &SumFilter{}
}
func (sf *SumFilter) Process(data Request) (Response, error) {
elems, ok := data.([]int)
if !ok {
return nil, SumFilterWrongFormatError
}
ret := 0
for _, elem := range elems {
ret += elem
}
return ret, nil
}
3症概、定義一個(gè)pipe-line蕾额, 目的是為了將所有的filter串起來(lái)。
pipe.go
package pipe_filter
// NewStraightPipeline create a new StraightPipelineWithWallTime
func NewStraightPipeline(name string, filters ...Filter) *StraightPipeline {
return &StraightPipeline{
Name: name,
Filters: &filters,
}
}
// StraightPipeline is composed of the filters, and the filters are piled as a straigt line.
type StraightPipeline struct {
Name string
Filters *[]Filter
}
// Process is to process the coming data by the pipeline
func (f *StraightPipeline) Process(data Request) (Response, error) {
var ret interface{}
var err error
for _, filter := range *f.Filters {
ret, err = filter.Process(data)
if err != nil {
return ret, err
}
data = ret
}
return ret, err
}
這下一個(gè)完美的 pipe-filter 就完成了
看下如何調(diào)用呢彼城?
package main
import (
"fmt"
"godemo/pipe-filter"
"log"
)
func main() {
spliter := pipe_filter.NewSplitFilter(",")
converter := pipe_filter.NewToIntFilter()
sum := pipe_filter.NewSumFilter()
sp := pipe_filter.NewStraightPipeline("p1", spliter, converter, sum)
ret, err := sp.Process("1,2,3")
if err != nil {
log.Fatal(err)
}
if ret != 6 {
log.Fatalf("The expected is 6, but the actual is %d", ret)
}
fmt.Println(ret)
}
執(zhí)行結(jié)果:
6