package main
import (
"context"
"errors"
"fmt"
"log"
"net/http"
)
type Request struct {
Data string
Name string
Upload string
}
type Response struct {
}
type Context struct {
Req *Request
Resp *Response
handlers []FilterFunc
index int
}
func (c *Context) Next() error {
c.index++
s := len(c.handlers)
for ; c.index <= s; c.index++ {
if err := c.handlers[c.index-1](c); err != nil {
return err
}
}
return nil
}
type Filter interface {
Handle(ctx *Context) error
}
type FilterFunc func(ctx *Context) error
type FilterDecorator struct {
filters []FilterFunc
}
func NewFilterDecorator() *FilterDecorator {
return &FilterDecorator{}
}
func (d *FilterDecorator) Use(middlewares ...FilterFunc) {
d.filters = append(d.filters, middlewares...)
}
func (d *FilterDecorator) Do(request *Request, response *Response) error {
c := new(Context)
c.Req = request
c.Resp = response
c.handlers = d.filters
return c.Next()
}
func ValidateParam() FilterFunc {
return func(ctx *Context) error {
req := ctx.Req
if req.Name != "Tom" {
return errors.New("name is not Tom")
}
ctx.Next()
return nil
}
}
func ProcessFilter() FilterFunc {
return func(ctx *Context) (err error) {
log.Println("processing ProcessFilter")
defer func() {
log.Println("after ProcessFilter")
}()
ctx.Req.Name = "Jack"
if err := ctx.Next(); err != nil {
return err
}
return nil
}
}
type Uploader interface {
Upload(ctx context.Context, data string) error
}
type UploaderFunc func(ctx context.Context, data string) error
func (u UploaderFunc) Upload(ctx context.Context, data string) error {
return u(ctx, data)
}
type AliyunClient struct {
c *http.Client
}
func NewAliyunClient() *AliyunClient {
return &AliyunClient{}
}
func (a *AliyunClient) Upload(ctx context.Context, data string) error {
log.Printf("AliyunClient Upload:%s", data)
return nil
}
type AwsClient struct {
c *http.Client
}
func NewAwsClient() *AwsClient {
return &AwsClient{}
}
func (a *AwsClient) Upload(ctx context.Context, data string) error {
log.Printf("AwsClient Upload:%s", data)
return nil
}
func AzureUpload() UploaderFunc {
return func(ctx context.Context, data string) error {
log.Printf("AzureClient Upload:%s", data)
return nil
}
}
func UploadFilter() FilterFunc {
aliyun := NewAliyunClient()
aws := NewAwsClient()
uploaderMap := map[string]Uploader{
"aliyun": aliyun,
"aws": aws,
"azure": AzureUpload(),
}
log.Println("--Hello World")
return func(ctx *Context) (err error) {
log.Println("processing UploadFilter")
fmt.Printf("Name:%s\n", ctx.Req.Name)
var uploader Uploader
uploader, ok := uploaderMap[ctx.Req.Upload]
if !ok {
uploader = aliyun
}
if err = uploader.Upload(context.Background(), ctx.Req.Data); err != nil {
return
}
if err := ctx.Next(); err != nil {
return err
}
return nil
}
}
func main() {
d := NewFilterDecorator()
d.Use(ValidateParam())
d.Use(ProcessFilter())
d.Use(UploadFilter())
req := new(Request)
req.Data = "Hello World"
req.Upload = "azure"
resp := new(Response)
if err := d.Do(req, resp); err != nil {
log.Println(err)
}
}
Go 实现责任链模式
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 责任链模式(chain of responsibility)是赫赫有名的GoF书中描述的23个经典模式之一。 这个...
- 上节中我们知道了 Sentinel-Go 大概能做什么事情,最简单的例子如何跑起来 其实我早就写好了本系列的第二篇...
- Day 12 神句文档 The team contends that these bear more than a...