责任链模式
责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。比如 kratos
,gin
等开源库的中间件实现。
代码实现
package main
import (
"context"
"fmt"
)
type Handler func(ctx context.Context, req interface{}) (resp interface{}, err error)
type Middleware func(next Handler) Handler
func Chain(middlewares ...Middleware) Middleware {
return func(next Handler) Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
next = middlewares[i](next)
}
return next
}
}
func main() {
c := Chain(func(next Handler) Handler {
return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
fmt.Println("handler 1 before")
resp, err = next(ctx, req)
fmt.Println("handler 1 after")
return resp, err
}
}, func(next Handler) Handler {
return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
fmt.Println("handler 2 before")
resp, err = next(ctx, req)
fmt.Println("handler 2 after")
return resp, err
}
})
resp, err := c(func(ctx context.Context, req interface{}) (resp interface{}, err error) {
fmt.Println("handler req:", req)
return req, nil
})(context.Background(), "hello")
fmt.Println(resp, err)
}
/*
handler 1 before
handler 2 before
handler req: hello
handler 2 after
handler 1 after
hello <nil>
*/
观察者模式
观察者模式用于触发联动。一个对象的改变会触发其它观察者的相关动作,而此对象无需关心连动对象的具体实现。
代码实现
package main
import "fmt"
type subject interface {
register(Observer observer)
deregister(Observer observer)
notifyAll()
}
type observer interface {
update(string)
getID() string
}
type item struct {
observerList []observer
name string
inStock bool
}
func newItem(name string) *item {
return &item{
name: name,
}
}
func (i *item) updateAvailability() {
fmt.Printf("Item %s is now in stock\n", i.name)
i.inStock = true
i.notifyAll()
}
func (i *item) register(o observer) {
i.observerList = append(i.observerList, o)
}
func (i *item) deregister(o observer) {
i.observerList = removeFromslice(i.observerList, o)
}
func (i *item) notifyAll() {
for _, observer := range i.observerList {
observer.update(i.name)
}
}
func removeFromslice(observerList []observer, observerToRemove observer) []observer {
observerListLength := len(observerList)
for i, observer := range observerList {
if observerToRemove.getID() == observer.getID() {
observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
return observerList[:observerListLength-1]
}
}
return observerList
}
type customer struct {
id string
}
func (c *customer) update(itemName string) {
fmt.Printf("Sending email to customer %s for item %s\n", c.id, itemName)
}
func (c *customer) getID() string {
return c.id
}
func main() {
shirtItem := newItem("Nike Shirt")
observerFirst := &customer{id: "abc@gmail.com"}
observerSecond := &customer{id: "xyz@gmail.com"}
shirtItem.register(observerFirst)
shirtItem.register(observerSecond)
shirtItem.updateAvailability()
}
/*
Item Nike Shirt is now in stock
Sending email to customer abc@gmail.com for item Nike Shirt
Sending email to customer xyz@gmail.com for item Nike Shirt
*/
模板方法模式
模版方法模式使用继承机制,把通用步骤和通用方法放到父类中,把具体实现延迟到子类中实现。使得实现符合开闭原则。
如实例代码中通用步骤在父类中实现(准备
、下载
、保存
、收尾
)下载和保存的具体实现留到子类中,并且提供 保存
方法的默认实现。
因为Golang不提供继承机制,需要使用匿名组合模拟实现继承。
此处需要注意:因为父类需要调用子类方法,所以子类需要匿名组合父类的同时,父类需要持有子类的引用。
代码实现
package main
import "fmt"
type Downloader interface {
Download(uri string)
}
type template struct {
implement
uri string
}
type implement interface {
download()
save()
}
func newTemplate(impl implement) *template {
return &template{
implement: impl,
}
}
func (t *template) Download(uri string) {
t.uri = uri
fmt.Print("prepare downloading\n")
t.implement.download()
t.implement.save()
fmt.Print("finish downloading\n")
}
func (t *template) save() {
fmt.Print("default save\n")
}
type HTTPDownloader struct {
*template
}
func NewHTTPDownloader() Downloader {
downloader := &HTTPDownloader{}
template := newTemplate(downloader)
downloader.template = template
return downloader
}
func (d *HTTPDownloader) download() {
fmt.Printf("download %s via http\n", d.uri)
}
func (*HTTPDownloader) save() {
fmt.Printf("http save\n")
}
type FTPDownloader struct {
*template
}
func NewFTPDownloader() Downloader {
downloader := &FTPDownloader{}
template := newTemplate(downloader)
downloader.template = template
return downloader
}
func (d *FTPDownloader) download() {
fmt.Printf("download %s via ftp\n", d.uri)
}
func main() {
downloader := NewHTTPDownloader()
downloader.Download("http://example.com/abc.zip")
downloader = NewFTPDownloader()
downloader.Download("ftp://example.com/abc.zip")
}
/*
prepare downloading
download http://example.com/abc.zip via http
http save
finish downloading
prepare downloading
download ftp://example.com/abc.zip via ftp
default save
finish downloading
*/