Golang中的一些设计模式

工厂模式

工厂模式,工厂模式一般用于初始化对象,将对象实例化的过程抽象,可以适配组装出不同的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
type User struct {
ID int64
Name string

Address string
Orgnize string
}

type Options func(user *User)

func NewUser(id int64, name string, opts ...Options) *User {
user := &User{
ID: id,
Name: name,
}

for _, o := range opts {
o(user)
}
return user
}

func WithAddress(user *User) {
user.Address = "Wuhan"
}

func WithOrgnize(user *User) {
user.Orgnize = "Developer"
}

func main() {
u := NewUser(1, "mitaka", WithOrgnize, WithAddress)
fmt.Println(u)
}

责任链模式

责任链模式通常会用到中间件中,例如Gin框架中使用recoverlog中间件,使用的就是责任链模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Handler func(writer http.ResponseWriter, request *http.Request)

func Hello(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello"))
}

// 责任链模式,以及装饰器模式,输入一个函数,输出一个函数。
func Filter(next Handler) Handler {
return func(writer http.ResponseWriter, request *http.Request) {
log.Println("get a http requese from: ", request.RemoteAddr)
start := time.Now()
next(writer, request)
log.Println("this request spend ", time.Now().Sub(start).String())
}
}

func main() {
http.HandleFunc("/", Filter(Hello))
}

封装和抽象

在实现一个框架的过程中,会经常使用到封装的能力,将相同的参数和请求疯转到一起,将功能封装到接口中。

例如将http请求中的请求和响应封装成一个结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import "net/http"

type Context struct {
w http.ResponseWriter
r *http.Request
}

func NewContext(w http.ResponseWriter, r *http.Request) *Context {
return &Context{w: w, r: r}
}

func (c *Context) ReplyOK() {
c.w.WriteHeader(http.StatusOK)
}

func (c *Context) ReplyNotFound() {
c.w.WriteHeader(http.StatusNotFound)
}

处理请求时,通过该请求即可。

将http请求封装成一个interface,通过内部接口实现http服务启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package main

import (
"net/http"
)

type Handler func(ctx *Context)

type HttpServerHandler interface {
Route(pattern string, handler Handler)
Start(addr string) error
Use(filters ...FilterFunc)
http.Handler
}

type HttpServer struct {
name string
Filters []FilterFunc
handlers map[string]Handler
}

var _ HttpServerHandler = &HttpServer{}

func NewHttpServer(name string) HttpServerHandler {
return &HttpServer{
name: name,
Filters: make([]FilterFunc, 0, 2),
handlers: make(map[string]Handler),
}
}

func (h *HttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c := NewContext(w, r)
handler, ok := h.handlers[c.r.URL.Path]
if !ok {
c.ReplyNotFound()
}
handler(c)
}

func (h *HttpServer) Route(pattern string, handler Handler) {
for _, filter := range h.Filters {
handler = filter(handler)
}
h.handlers[pattern] = handler
http.Handle(pattern, h)
}

func (h *HttpServer) Start(addr string) error {
return http.ListenAndServe(addr, nil)
}

func (h *HttpServer) Use(filters ...FilterFunc) {
h.Filters = append(h.Filters, filters...)
}

其中,使用Use方法添加中间件。中间件则使用了责任链的设计模式或者装饰器设计模式

1
2
3
4
5
6
7
8
9
10
type FilterFunc func(next Handler) Handler

func LogFilter(next Handler) Handler {
return func(ctx *Context) {
log.Println("get a http requese from: ", ctx.r.RemoteAddr)
start := time.Now()
next(ctx)
log.Println("this request spend ", time.Now().Sub(start).String())
}
}