go 常用设计模式-行为型模式

发布时间 2023-03-22 21:10:59作者: Marathon-Davis

本次分享的行为型模式,主要包含:

  • 责任链模式
  • 策略模式
  • 观察者模式
  • 模板模式
  • 访问者模式

1.责任链模式

package chainOfResponsibility

import "fmt"

/*
行为模式:
通过账目报销的例子说明,不同的级别领导,其权限不同,如100元级别,100元级别等
 */
type ChainResponsibility interface {
	Approve(money int)
}

// define multiple role, staff/manager/CEO
type Staff struct {
	Next ChainResponsibility
}

func (s Staff) Approve(money int)  {
	if money >= 0 && money < 100 {
		fmt.Println("Staff 通过审批")
	} else {
		fmt.Println("Staff 无权限审批,传递给上级")
		s.Next.Approve(money)
	}
}

type Manager struct {
	Next ChainResponsibility
}

func (m Manager) Approve(money int)  {
	if money >= 100 && money < 1000 {
		fmt.Println("Manager 通过审批")
	} else {
		fmt.Println("Manager 无权限审批,传递给上级")
		m.Next.Approve(money)
	}
}

type CEO struct {
	Next ChainResponsibility
}

func (c CEO) Approve(money int)  {
	if money >= 1000 {
		fmt.Println("CEO 审批完成")
	} else {
		fmt.Println("CEO 驳回审批")
	}
	return
}

2.策略模式

package strategy

/*
行为型模式
*/

type Strategy interface {
	Calculate(a, b int) int
}

// implement strategy
type Add struct {}

func (s Add) Calculate(a, b int) int {
	return a + b
}

type Sub struct {}

func (s Sub) Calculate(a, b int) int {
	return a - b
}

// define real strategy dispatcher
type Calculator struct {
	s Strategy
}

func (c *Calculator) SetStrategy(s Strategy)  {
	c.s = s
}

func (c Calculator) GetResult(a, b int) int {
	return c.s.Calculate(a, b)
}

3.观察者模式

package observer

import "fmt"

/*
行为型模式
对于观察者只需要预留好针对通知的处理接口即可,对于目标对象需要知道最终结果通知给谁。
先定义观察者,为了代码的可复用性,将观察者定义为接口类型
*/

// different observer has specific handle logic
type Observer interface {
	Response(msg string)
}

// instance observer
type ConcreteObserver struct {
	Username string
}

func (t *ConcreteObserver) Response(msg string)  {
	fmt.Println(t.Username + ": " + msg)
}

// 目标对象
type Subject interface {
	Add(o Observer)
	Remove(o Observer)
	Notify()
}

// instance subject
type ConcreteSubject struct {
	obs []Observer
}

func (t *ConcreteSubject) Add(o Observer)  {
	t.obs = append(t.obs, o)
}

func (t *ConcreteSubject) Remove(o Observer)  {
	for i, v := range t.obs {
		if v == o {
			t.obs = append(t.obs[0:i], t.obs[i+1:]...)
			return
		}
	}
	return
}

func (t *ConcreteSubject) Notify()  {
	for _, v := range t.obs {
		v.Response("你有一条好消息。")
	}
}

4.模板模式

package template

import "fmt"

/*
行为型模式
模板方法模式很像许多一成不变的东西,都会有一种固定的运行模式,要做的只是在该模式的基础上做略微的调整。

项目通用的流程包括设计、开发、测试、发布,这里就抽象化一个Product
*/

type Product interface {
	Design()
	Develop()
	Test()
	Release()
}

// instance to implement interface
type ConcreteProductA struct {}

func (c ConcreteProductA) Design()  {
	fmt.Println("设计A")
}

func (c ConcreteProductA) Develop()  {
	fmt.Println("开发A")
}

func (c ConcreteProductA) Test()  {
	fmt.Println("测试A")
}

func (c ConcreteProductA) Release()  {
	fmt.Println("发布A")
}

type ConcreteProductB struct {}

func (c ConcreteProductB) Design()  {
	fmt.Println("设计B")
}

func (c ConcreteProductB) Develop()  {
	fmt.Println("开发B")
}

func (c ConcreteProductB) Test()  {
	fmt.Println("测试B")
}

func (c ConcreteProductB) Release()  {
	fmt.Println("发布B")
}

5.访问者模式

package visitor

import "fmt"

/*
行为型模式

将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,
使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。
*/

// 比如消费者去超市买水果,普通、vip顾客享受不同的优惠
// 为了扩展,定义接口
type Visitor interface {
	BuyApple(a Apple)
	BuyBanana(b Banana)
	BuyStrawberry(c Strawberry)
}

// implement 2 kinds consumer
type VipVisitor struct {
	Discount float64
}

func (t VipVisitor) BuyApple(a Apple)  {
	fmt.Println("苹果原价:", a.GetPrice(), "会员价格:", t.Discount*float64(a.GetPrice()))
}

func (t VipVisitor) BuyBanana(b Banana) {
	fmt.Println("香蕉原价:", b.GetPrice(), "会员价格购:", t.Discount*float64(b.GetPrice()))
}

func (t VipVisitor) BuyStrawberry(c Strawberry) {
	fmt.Println("草莓原价:", c.GetPrice(), "会员价格", t.Discount*float64(c.GetPrice()))
}

type NormalVisitor struct {
	discount float64
}

func (t NormalVisitor) BuyApple(a Apple)  {
	fmt.Println("苹果原价:", a.GetPrice(), "会员价格:", a.GetPrice())
}

func (t NormalVisitor) BuyBanana(b Banana) {
	fmt.Println("香蕉原价:", b.GetPrice(), "会员价格购:", b.GetPrice())
}

func (t NormalVisitor) BuyStrawberry(c Strawberry) {
	fmt.Println("草莓原价:", c.GetPrice(), "会员价格", c.GetPrice())
}


// define fruits
type Fruits interface {
	Accept(v Visitor)
	GetPrice() float64
}
type Apple struct {
	Price float64
}

func (t Apple) Accept(v Visitor)  {
	v.BuyApple(t)
}

func (t Apple) GetPrice() float64 {
	return t.Price
}

type Banana struct {
	Price float64
}

func (t Banana) Accept(v Visitor)  {
	v.BuyBanana(t)
}

func (t Banana) GetPrice() float64 {
	return t.Price
}
type Strawberry struct {
	Price float64
}

func (t Strawberry) Accept(v Visitor)  {
	v.BuyStrawberry(t)
}

func (t Strawberry) GetPrice() float64 {
	return t.Price
}

6.测试

...

func main {
        fmt.Println(strings.Repeat("-", 10) + "行为型模式" + strings.Repeat("-", 10))
	// 5.chain of responsibility mode
	fmt.Println("chain of responsibility mode testing...")
	s := &Staff{Next: &Manager{Next: CEO{}}}
	s.Approve(150)
	fmt.Println(strings.Repeat("-", 30))
	s.Approve(1000)
	fmt.Printf("+%s+\n", strings.Repeat("-", 50))

	// 6.strategy mode
	fmt.Println("strategy mode testing...")
	add := strategy.Add{}
	sub := strategy.Sub{}
	// set diff strategy, and dispatch it
	cal := &strategy.Calculator{}
	cal.SetStrategy(add)
	fmt.Println("加法策略结果:", cal.GetResult(10, 10))
	cal.SetStrategy(sub)
	fmt.Println("减法策略结果:", cal.GetResult(10, 10))
	fmt.Printf("+%s+\n", strings.Repeat("-", 50))

	// 7.observer mode
	fmt.Println("observer mode testing...")
	ob1 := &observer.ConcreteObserver{Username: "小明"}
	ob2 := &observer.ConcreteObserver{Username: "小红"}
	sub1 := &observer.ConcreteSubject{}
	sub1.Notify()
	sub1.Add(ob1)
	sub1.Add(ob2)
	sub1.Notify()
	fmt.Println("移除观察者:", ob1.Username)
	sub1.Remove(ob1)
	sub1.Notify()
	fmt.Printf("+%s+\n", strings.Repeat("-", 50))

	// 8.template mode
	fmt.Println("template mode testing...")
	proA := template.ConcreteProductA{}
	proB := template.ConcreteProductB{}
	proA.Design()
	proA.Develop()
	proA.Test()
	proA.Release()
	fmt.Println(strings.Repeat("-", 30))
	proB.Design()
	proB.Develop()
	proB.Test()
	proB.Release()
	fmt.Printf("+%s+\n", strings.Repeat("-", 50))

	// 9.visitor mode
	fmt.Println("visitor mode testing...")
	normalConsumer := visitor.NormalVisitor{}
	vipConsumer := visitor.VipVisitor{Discount: 0.98}
	f := make([]visitor.Fruits, 3)
	f[0] = visitor.Apple{Price: 6.8}
	f[1] = visitor.Banana{Price: 5.5}
	f[2] = visitor.Strawberry{Price: 19.8}
	for _, fruit := range f {
		fruit.Accept(normalConsumer)
		fruit.Accept(vipConsumer)
	}
	fmt.Printf("+%s+\n", strings.Repeat("-", 50))

	fmt.Println(strings.Repeat("-", 10) + "结构型模式" + strings.Repeat("-", 10))

}
...

参考文档: