首页 > 其他分享 >行为模式

行为模式

时间:2023-06-26 23:47:47浏览次数:45  
标签:return struct 行为 fmt 模式 func type string

责任链模式

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。比如 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: "[email protected]"}
	observerSecond := &customer{id: "[email protected]"}

	shirtItem.register(observerFirst)
	shirtItem.register(observerSecond)

	shirtItem.updateAvailability()
}

/*
Item Nike Shirt is now in stock
Sending email to customer [email protected] for item Nike Shirt
Sending email to customer [email protected] 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

https://refactoringguru.cn/design-patterns

https://lailin.xyz/post/singleton.html

标签:return,struct,行为,fmt,模式,func,type,string
From: https://www.cnblogs.com/haiyux/p/17507458.html

相关文章

  • 结构型模式
    适配器模式适配器模式用于转换一种接口适配另一种接口。比如,现在有个借口是对json字符串进行分析等,现在有一些yaml文件也要分析,这时候我我们就应该给yaml字符串就个适配器,转换成json字符串,然后就行分析。代码实现packagemainimport( "fmt" "github.com/ghodss/yaml")......
  • 结构型模式概述
    结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。......
  • 桥接模式
    目录1.概述2.结构3.案例4.使用场景1.概述现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系:我们可以发现有很多的类,假如我们再增加一个形状或再增加一种颜色,就需要创建更多的类。试想,在一个有多种可能会变化......
  • 组合模式详解
    简介组合模式(Composite)是针对由多个节点对象(部分)组成的树形结构的对象(整体)而发展出的一种结构型设计模式,它能够使客户端在操作整体对象或者其下的每个节点对象时做出统一的响应,保证树形结构对象使用方法的一致性,使客户端不必关注对象的整体或部分,最终达到对象复杂的层次结构与......
  • F5APM第七期Network Access模式配置
    F5APM第七期NetworkAccess模式配置’......
  • F5APM第六期Portal Access模式配置
    F5APM第六期PortalAccess模式配置Portal_conn......
  • 一文掌握设计模式(定义+UML类图+应用)
    一、引子从学编程一开始就被告知,要想做一名优秀的程序员两大必要技能:1.源码阅读(JDK、C等底层语言封装)2.设计模式(使用某种语言优雅的落地典型场景功能)。一般随着工作年限的增长,被迫对底层语言/框架源码阅读的越来愈多,但是设计模式如不刻意去学习,永远不会真正掌握。笔者把设计......
  • 结构型模式-静态代理模式
    #模式类型:结构性模型#模型方法:静态代理模式#作用:在不修改目标代码的情况下,可以控制目标代码的访问,可以在其前后添加自己的业务代码#使用场景:监控。日志,限流fromabcimportABCMeta,abstractmethodclassITeacher(metaclass=ABCMeta):"""教师接口"""@abs......
  • epoll的两种触发模式
    epoll有两种模式,EdgeTriggered(简称ET)和LevelTriggered(简称LT).在采用这两种模式时要注意的是,如果采用ET模式,那么仅当状态发生变化时才会通知,而采用LT模式类似于原来的select/poll操作,只要还有没有处理的事件就会一直通知. 以代码来说明问题: 首先给出server的代......
  • java使用AES算法的CBC模式加密
    https://blog.csdn.net/qq_25816185/article/details/81626499?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-81626499-blog-121345545.235%5Ev38%5Epc_relevant_sort&depth_1-utm_source=distribute......