行为模式
作者:@daemon365
本文为作者原创,转载请注明出处:https://www.cnblogs.com/daemon365/p/17507458.html
责任链模式
责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。比如 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 */
命令模式
命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
命令模式本质是把某个对象的方法调用封装到对象中,方便传递、存储、调用。
示例中把主板单中的启动(start)方法和重启(reboot)方法封装为命令对象,再传递到主机(box)对象中。于两个按钮进行绑定:
- 第一个机箱(box1)设置按钮1(button1) 为开机按钮2(button2)为重启。
- 第二个机箱(box1)设置按钮2(button2) 为开机按钮1(button1)为重启。
从而得到配置灵活性。
除了配置灵活外,使用命令模式还可以用作:
- 批处理
- 任务队列
- undo, redo
等把具体命令封装到对象中使用的场合
代码实现
package command import "fmt" type Command interface { Execute() } type StartCommand struct { mb *MotherBoard } func NewStartCommand(mb *MotherBoard) *StartCommand { return &StartCommand{ mb: mb, } } func (c *StartCommand) Execute() { c.mb.Start() } type RebootCommand struct { mb *MotherBoard } func NewRebootCommand(mb *MotherBoard) *RebootCommand { return &RebootCommand{ mb: mb, } } func (c *RebootCommand) Execute() { c.mb.Reboot() } type MotherBoard struct{} func (*MotherBoard) Start() { fmt.Print("system starting\n") } func (*MotherBoard) Reboot() { fmt.Print("system rebooting\n") } type Box struct { button1 Command button2 Command } func NewBox(button1, button2 Command) *Box { return &Box{ button1: button1, button2: button2, } } func (b *Box) PressButton1() { b.button1.Execute() } func (b *Box) PressButton2() { b.button2.Execute() }
策略模式
它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。
代码实现
package main import "fmt" type Payment struct { context *PaymentContext strategy PaymentStrategy } type PaymentContext struct { Name, CardID string Money int } func NewPayment(name, cardid string, money int, strategy PaymentStrategy) *Payment { return &Payment{ context: &PaymentContext{ Name: name, CardID: cardid, Money: money, }, strategy: strategy, } } func (p *Payment) Pay() { p.strategy.Pay(p.context) } type PaymentStrategy interface { Pay(*PaymentContext) } type Cash struct{} func (*Cash) Pay(ctx *PaymentContext) { fmt.Printf("Pay $%d to %s by cash\n", ctx.Money, ctx.Name) } type Bank struct{} func (*Bank) Pay(ctx *PaymentContext) { fmt.Printf("Pay $%d to %s by bank account %s\n", ctx.Money, ctx.Name, ctx.CardID) } func main() { payment := NewPayment("Ada", "", 123, &Cash{}) payment.Pay() payment = NewPayment("Bob", "0002", 888, &Bank{}) payment.Pay() } /* Pay $123 to Ada by cash Pay $888 to Bob by bank account 0002 */
状态模式
让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。
代码实现
package main import ( "fmt" ) // Machine 状态机 type Machine struct { state IState } // SetState 更新状态 func (m *Machine) SetState(state IState) { m.state = state } // GetStateName 获取当前状态 func (m *Machine) GetStateName() string { return m.state.GetName() } func (m *Machine) Approval() { m.state.Approval(m) } func (m *Machine) Reject() { m.state.Reject(m) } // IState 状态 type IState interface { // 审批通过 Approval(m *Machine) // 驳回 Reject(m *Machine) // 获取当前状态名称 GetName() string } // leaderApproveState 直属领导审批 type leaderApproveState struct{} // Approval 获取状态名字 func (leaderApproveState) Approval(m *Machine) { fmt.Println("leader 审批成功") m.SetState(GetFinanceApproveState()) } // GetName 获取状态名字 func (leaderApproveState) GetName() string { return "LeaderApproveState" } // Reject 获取状态名字 func (leaderApproveState) Reject(m *Machine) {} func GetLeaderApproveState() IState { return &leaderApproveState{} } // financeApproveState 财务审批 type financeApproveState struct{} // Approval 审批通过 func (f financeApproveState) Approval(m *Machine) { fmt.Println("财务审批成功") fmt.Println("出发打款操作") } // 拒绝 func (f financeApproveState) Reject(m *Machine) { m.SetState(GetLeaderApproveState()) } // GetName 获取名字 func (f financeApproveState) GetName() string { return "FinanceApproveState" } // GetFinanceApproveState GetFinanceApproveState func GetFinanceApproveState() IState { return &financeApproveState{} } func main() { m := &Machine{state: GetLeaderApproveState()} fmt.Println("LeaderApproveState", m.GetStateName()) m.Approval() fmt.Println("FinanceApproveState", m.GetStateName()) m.Reject() fmt.Println("LeaderApproveState", m.GetStateName()) m.Approval() fmt.Println("FinanceApproveState", m.GetStateName()) m.Approval() } /* LeaderApproveState LeaderApproveState leader 审批成功 FinanceApproveState FinanceApproveState LeaderApproveState LeaderApproveState leader 审批成功 FinanceApproveState FinanceApproveState 财务审批成功 出发打款操作 */
迭代器模式
让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。
代码实现
package main import "fmt" type collection interface { createIterator() iterator } type userCollection struct { users []*user } func (u *userCollection) createIterator() iterator { return &userIterator{ users: u.users, } } type iterator interface { hasNext() bool getNext() *user } type userIterator struct { index int users []*user } func (u *userIterator) hasNext() bool { if u.index < len(u.users) { return true } return false } func (u *userIterator) getNext() *user { if u.hasNext() { user := u.users[u.index] u.index++ return user } return nil } type user struct { name string age int } func main() { user1 := &user{ name: "a", age: 30, } user2 := &user{ name: "b", age: 20, } userCollection := &userCollection{ users: []*user{user1, user2}, } iterator := userCollection.createIterator() for iterator.hasNext() { user := iterator.getNext() fmt.Printf("User is %+v\n", user) } } /* User is &{name:a age:30} User is &{name:b age:20} */
访问者模式
访问者模式可以给一系列对象透明的添加功能,并且把相关代码封装到一个类中。
对象只要预留访问者接口Accept
则后期为对象添加功能的时候就不需要改动对象。
代码实现
package main import "fmt" type Customer interface { Accept(Visitor) } type Visitor interface { Visit(Customer) } type EnterpriseCustomer struct { name string } type CustomerCol struct { customers []Customer } func (c *CustomerCol) Add(customer Customer) { c.customers = append(c.customers, customer) } func (c *CustomerCol) Accept(visitor Visitor) { for _, customer := range c.customers { customer.Accept(visitor) } } func NewEnterpriseCustomer(name string) *EnterpriseCustomer { return &EnterpriseCustomer{ name: name, } } func (c *EnterpriseCustomer) Accept(visitor Visitor) { visitor.Visit(c) } type IndividualCustomer struct { name string } func NewIndividualCustomer(name string) *IndividualCustomer { return &IndividualCustomer{ name: name, } } func (c *IndividualCustomer) Accept(visitor Visitor) { visitor.Visit(c) } type ServiceRequestVisitor struct{} func (*ServiceRequestVisitor) Visit(customer Customer) { switch c := customer.(type) { case *EnterpriseCustomer: fmt.Printf("serving enterprise customer %s\n", c.name) case *IndividualCustomer: fmt.Printf("serving individual customer %s\n", c.name) } } // only for enterprise type AnalysisVisitor struct{} func (*AnalysisVisitor) Visit(customer Customer) { switch c := customer.(type) { case *EnterpriseCustomer: fmt.Printf("analysis enterprise customer %s\n", c.name) } } func main() { c := &CustomerCol{} c.Add(NewEnterpriseCustomer("A company")) c.Add(NewEnterpriseCustomer("B company")) c.Add(NewIndividualCustomer("bob")) c.Accept(&ServiceRequestVisitor{}) c = &CustomerCol{} c.Add(NewEnterpriseCustomer("A company")) c.Add(NewIndividualCustomer("bob")) c.Add(NewEnterpriseCustomer("B company")) c.Accept(&AnalysisVisitor{}) } /* serving enterprise customer A company serving enterprise customer B company serving individual customer bob analysis enterprise customer A company analysis enterprise customer B company */
备忘录模式
备忘录模式用于保存程序内部状态到外部,又不希望暴露内部状态的情形。
程序内部状态使用窄接口传递给外部进行存储,从而不暴露程序实现细节。
备忘录模式同时可以离线保存内部状态,如保存到数据库,文件等。
代码实现
package main import "fmt" type Memento interface{} type Game struct { hp, mp int } type gameMemento struct { hp, mp int } func (g *Game) Play(mpDelta, hpDelta int) { g.mp += mpDelta g.hp += hpDelta } func (g *Game) Save() Memento { return &gameMemento{ hp: g.hp, mp: g.mp, } } func (g *Game) Load(m Memento) { gm := m.(*gameMemento) g.mp = gm.mp g.hp = gm.hp } func (g *Game) Status() { fmt.Printf("Current HP:%d, MP:%d\n", g.hp, g.mp) } func main() { game := &Game{ hp: 10, mp: 10, } game.Status() progress := game.Save() game.Play(-2, -3) game.Status() game.Load(progress) game.Status() } /* Current HP:10, MP:10 Current HP:7, MP:8 Current HP:10, MP:10 */
解释器模式
解释器模式定义一套语言文法,并设计该语言解释器,使用户能使用特定文法控制解释器行为。
解释器模式的意义在于,它分离多种复杂功能的实现,每个功能只需关注自身的解释。
对于调用者不用关心内部的解释器的工作,只需要用简单的方式组合命令就可以。
代码实现
package main import ( "fmt" "strconv" "strings" ) type Node interface { Interpret() int } type ValNode struct { val int } func (n *ValNode) Interpret() int { return n.val } type AddNode struct { left, right Node } func (n *AddNode) Interpret() int { return n.left.Interpret() + n.right.Interpret() } type MinNode struct { left, right Node } func (n *MinNode) Interpret() int { return n.left.Interpret() - n.right.Interpret() } type Parser struct { exp []string index int prev Node } func (p *Parser) Parse(exp string) { p.exp = strings.Split(exp, " ") for { if p.index >= len(p.exp) { return } switch p.exp[p.index] { case "+": p.prev = p.newAddNode() case "-": p.prev = p.newMinNode() default: p.prev = p.newValNode() } } } func (p *Parser) newAddNode() Node { p.index++ return &AddNode{ left: p.prev, right: p.newValNode(), } } func (p *Parser) newMinNode() Node { p.index++ return &MinNode{ left: p.prev, right: p.newValNode(), } } func (p *Parser) newValNode() Node { v, _ := strconv.Atoi(p.exp[p.index]) p.index++ return &ValNode{ val: v, } } func (p *Parser) Result() Node { return p.prev } func main() { p := &Parser{} p.Parse("1 + 2 + 3 - 4 + 5 - 6") res := p.Result().Interpret() expect := 1 if res != expect { fmt.Println(res,expect) } }
中介模式
中介者模式封装对象之间互交,使依赖变的简单,并且使复杂互交简单化,封装在中介者中。
例子中的中介者使用单例模式生成中介者。
中介者的change使用switch判断类型。
代码实现
package main import ( "fmt" "strings" ) type CDDriver struct { Data string } func (c *CDDriver) ReadData() { c.Data = "music,image" fmt.Printf("CDDriver: reading data %s\n", c.Data) GetMediatorInstance().changed(c) } type CPU struct { Video string Sound string } func (c *CPU) Process(data string) { sp := strings.Split(data, ",") c.Sound = sp[0] c.Video = sp[1] fmt.Printf("CPU: split data with Sound %s, Video %s\n", c.Sound, c.Video) GetMediatorInstance().changed(c) } type VideoCard struct { Data string } func (v *VideoCard) Display(data string) { v.Data = data fmt.Printf("VideoCard: display %s\n", v.Data) GetMediatorInstance().changed(v) } type SoundCard struct { Data string } func (s *SoundCard) Play(data string) { s.Data = data fmt.Printf("SoundCard: play %s\n", s.Data) GetMediatorInstance().changed(s) } type Mediator struct { CD *CDDriver CPU *CPU Video *VideoCard Sound *SoundCard } var mediator *Mediator func GetMediatorInstance() *Mediator { if mediator == nil { mediator = &Mediator{} } return mediator } func (m *Mediator) changed(i interface{}) { switch inst := i.(type) { case *CDDriver: m.CPU.Process(inst.Data) case *CPU: m.Sound.Play(inst.Sound) m.Video.Display(inst.Video) } } func main() { mediator := GetMediatorInstance() mediator.CD = &CDDriver{} mediator.CPU = &CPU{} mediator.Video = &VideoCard{} mediator.Sound = &SoundCard{} //Tiggle mediator.CD.ReadData() fmt.Printf("%#v\n", mediator) } /* CDDriver: reading data music,image CPU: split data with Sound music, Video image SoundCard: play music VideoCard: display image &main.Mediator{CD:(*main.CDDriver)(0xc000010250), CPU:(*main.CPU)(0xc000060040), Video:(*main.VideoCard)(0xc000010260), Sound:(*main.SoundCard)(0xc000010270)} */
References
https://github.com/senghoo/golang-design-pattern
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?