首页 > 其他分享 >go设计模式之行为型模式

go设计模式之行为型模式

时间:2022-12-11 10:07:09浏览次数:58  
标签:code return string fmt 模式 func go 设计模式 type

行为模式解决什么问题

行为型模式关注对象之间的通信和职责委派。下面介绍go中比较常用的3种设计模式分别是策略模式,模版模式,观察者模式。

1.策略模式

策略模式将一组行为分别封装成不同对象,使得这些对象可以根据需要任意替换,而不影响原有代码的逻辑流程。其本质是通过接口,解耦行为和调用该行为的对象。 最常见的应用场景就是缓存库的设计,需要根据实际需要自行选择和灵活替换缓存淘汰算法(常见的有LRU,FIFO,LFU),甚至自定义缓存淘汰算法,而我们只需要实现缓存淘汰算法所规定的方法 就可以替换不用的策略,需要注意的是为了方便替换,我们往往会设置下属代码中诸如setEvictStrategy()的方法进行策略替换。

package main

import "fmt"

// 策略接口
type EvictionAlgorithm interface {
	evict()
}

type Lru struct {
}

// lru 的实现
func (c Lru) evict() {
	fmt.Println("evicting by lru strategy")
}

type Fifo struct {
}

// fifo 的实现
func (c Fifo) evict() {
	fmt.Println("evicting by fifo strategy")
}

type Cache struct {
	storage           map[string]string
	evictionAlgorithm EvictionAlgorithm
	capacity          int
	maxCapacity       int
}

func NewCache(e EvictionAlgorithm) *Cache {
	return &Cache{
		storage:           make(map[string]string, 0),
		evictionAlgorithm: e,
		capacity:          0,
		maxCapacity:       0,
	}
}

// 设置策略
func (c *Cache) setEvictStrategy(e EvictionAlgorithm) {
	c.evictionAlgorithm = e
}

func (c *Cache) evict(){
	c.evictionAlgorithm.evict()
	c.capacity--
}

func (c *Cache) Add(k, v string) {
	if c.capacity >= c.maxCapacity {
		c.evict()
	}

	c.storage[k] = v
	c.capacity++
}

func main() {
	CacheClient := NewCache(nil)

	lurStrategy := Lru{}
	CacheClient.setEvictStrategy(lurStrategy)

	CacheClient.Add("a","1")
	CacheClient.Add("b","2")


	fifoStrategy := Fifo{}
	CacheClient.setEvictStrategy(fifoStrategy)

	CacheClient.Add("a","1")
	CacheClient.Add("b","2")


}

2.模版模式

模版模式在基类中定义了一系列的逻辑(算法,业务逻辑)的框架,可以通过子类重写逻辑的特定步骤,而不修改原有结构。其本质是将公共的方法放到抽象类中,而通同接口将 不能通用的方法定义为接口,让实现了接口的子类去实现这部分差异的方法。下面代码演示了一种场景,给用户发送验证码,可以有短信和邮件两种方式,而在这之前的 业务逻辑是共用的,例如第一步生成验证码,第二步保存验证码...,因此像这种操作步骤的流程是相同的只是某几个实现方式不同的场景就可以使用模版模式。

package main

import "fmt"

type IVerificationCode interface {
	genCode() string
	saveCode(code string) error
	getMsg(code string) string
	sendMsg(msg string) error
}

func genAndSendCode(opt IVerificationCode) error {
	code := opt.genCode()

	if err := opt.saveCode(code); err != nil {
		return err
	}
	msg := opt.getMsg(code)

	if err := opt.sendMsg(msg); err != nil {
		return err
	}

	return nil
}

// 公共部分抽象
type CodePart struct {
}

func (c CodePart) genCode() string {
	return "1234"
}

func (c CodePart) getMsg(code string) string {
	return fmt.Sprintf("你的验证码是:%s", code)

}

func (c CodePart) saveCode(code string) error {
	fmt.Printf("服务端保存了验证码:%s\n", code)
	return nil
}

type SmsCode struct {
	CodePart
}

func (s SmsCode) sendMsg(code string) error {
	fmt.Println("通过短信的方式发送了验证码")
	return nil
}

type EmailCode struct {
	CodePart
}

func (e EmailCode) sendMsg(code string) error {
	fmt.Println("通过邮件的方式发送了验证码")
	return nil
}

func main() {

	sms := SmsCode{}

	if err := genAndSendCode(sms); err != nil {
		return
	}

	email := EmailCode{}

	if err := genAndSendCode(email); err != nil {
		return
	}

}

3.观察者模式

观察者模式提供了一种把一个对象其状态的变更,通知给实现了订阅者接口的对象(观察者)的机制,同时其他对象(观察者)可以此对象(被观察的对象)进行订阅和取消订阅。其本质是通过接口解耦通知对象和 被通知对象这种一对多的关系,使得通知对象和接口,接口和被通知对象简化为简单的一对一关系。 下面的代码实现了当某个商品有库存的时候,通知订阅了这个商品上架提醒的顾客

package main

import "fmt"

type Subject interface {
	register(observer Observer)
	deregister(observer Observer)
	notifyAll()
}

type Item struct {
	observerList []Observer
	name         string
	inStock      bool
}

func NewItem(name string) Item {
	return Item{name: name}
}

func (i *Item) register(observer Observer) {
	i.observerList = append(i.observerList, observer)
}

func (i *Item) deregister(observer Observer) {
	// todo remove observer from observerList
}

func (i *Item) notifyAll() {
	for _, v := range i.observerList {
		v.update(i.name)
	}
}

func (i Item) updateAvailability() {
	fmt.Printf("item %s is now in stock\n", i.name)
	i.inStock = true
	i.notifyAll()
}

type Observer interface {
	update(string)
}

type Customs struct {
	id string
}

func (c Customs) update(name string) {
	fmt.Printf("send email to customer %s for item %s\n", c.id, name)
}

func main() {
	book := NewItem("《设计模式:可复用面向对象软件的基础》")

	book.register(&Customs{id: "[email protected]"})
	book.register(&Customs{id: "[email protected]"})

	book.updateAvailability()

}

4.总结

下面是分别是这3种设计模式的应用场景:

设计模式 常见应用场景
策略模式 按照实际需求要对系统的算法做任意替换,而不影响原有代码
模版模式 固定的流程和逻辑,但不同对象在某些步骤上的实现方式有差别
观察者模式 一个对象(被观察者)需要将其状态的变化通知其他对象(观察者)

公众号

标签:code,return,string,fmt,模式,func,go,设计模式,type
From: https://blog.51cto.com/u_15023762/5928044

相关文章

  • ArgoDB 5.1 正式发布:多模融合、实时分析和数据安全多重升级
    TranswarpArgoDB是星环科技自主研发的高性能分布式分析型数据库,在PB级数据量上提供极致的数据分析能力。ArgoDB支持标准SQL语法和分布式事务,提供高并发高速数据......
  • go 的 wire 依赖注入
    go文件packagemainimport( "fmt" "github.com/google/wire")varDbSet=wire.NewSet(NewDb,NewDao)typeDbstruct{ connectstring}typeDaostruct......
  • Command模式
    一般command大概interface:structICommand{virtualvoidexecute()=0;virtualvoidundo()=0;} 今年cppCon讲了一种非常简单的static模式实现:Us......
  • django框架(部分讲解)
    静态文件配置1.编写一个用户登录页面2.静态文件 不怎么经常变化的文件主要针对html文件所使用的到的各种资源 css文件、js文件、img文件、第三方框架文件 djan......
  • django02
    .静态文件配置不经常变化的文件,主要针对html文件所使用到的各种资源就是静态文件(css文件、js文件、img文件、第三方框架文件)针对静态文件资源需创建一个static目录统......
  • Go语言基础之运算符
    运算符运算符用于在程序运行时执行数学或逻辑运算。Go语言内置的运算符有:算术运算符关系运算符逻辑运算符位运算符赋值运算符算术运算符运算符描述......
  • 把时间沉淀下来 | Kagol 的 2022 年终总结
    现代管理学之父德鲁克在其经典著作《卓有成效的管理者》中对时间有一段精妙的论述,其要点如下:时间是一项限制因素,任何生产程序的产出量,都会受到最稀有资源的制约,而时间就......
  • Go-14 Golang语言中 函数详解之defer延迟处理函数和return的结合使用
    packagemain//defer延迟处理函数和return的结合运用/* 按照下面的示例作了一个总结,文字结合下面的代码更容易理解 总结一下规则: defer里面的变量必须与函数定义的......
  • 静态文件配置,from表单,request对象,pycharm连接数据库,Django连接数据库,初识ORM
    目录静态文件配置,from表单,request对象,pycharm连接数据库,Django连接数据库,初识ORM今日内容概要今日内容详细静态文件配置静态文件相关配置form表单request对象pycharm连接数......
  • Go语言之基本数据类型
    Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通道(channel)等。Go语言的基本类型和其他语言大同小异。基本数......