go 编程的架构模式(pipe-filter)

OOM_Killer · · 1200 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

架构模式,可以使你的代码可复用性高,代码整洁,如果不用架构模式写出来的代码就是字符的堆砌,没有美感。
掌握了golang的基础之后,就应该在之后的代码中以架构模式的方式去编程。
第一种架构模式 pipe-filter

pipe-filter
  • 其架构适用于 解析,过滤,处理,返回这样的架构,如数据分析。
  • filter 用于数据的过滤。而pipe 用于连接filter传递数据,或者异步处理缓冲数据流。
  • 松耦合:filter 只和数据耦合。


    pipe-filter

下面的例子是一个将 字符串“1,2,3” 按逗号切分后,再字符转数字相加的过程。


pipe-filter

1、首先实现一个 filter 的接口。该接口定义了数据的来源接口,输出接口,该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、定义一个pipe-line, 目的是为了将所有的filter串起来。
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
}

3、定义需要的filter,在这里filter的工作顺序是串行的,首先是按“,”拆分,其次将字符型转换为数字形。最后加起来。每个filter都必须实现一个Process方法,因为只是在filter.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) //检查数据格式/类型,是否可以处理
    if !ok {
        return nil, SplitFilterWrongFormatError
    }
    parts := strings.Split(str, sf.delimiter)
    return parts, nil
}

toint_filter.go (字符转整数)

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
}

这下一个完美的 pipe-filter 就完成了
看下如何调用呢?

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)
}

执行结果:
6

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:OOM_Killer

查看原文:go 编程的架构模式(pipe-filter)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1200 次点击  
加入收藏 微博
下一篇:2019-08-07
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传