Go语言实现23种设计模式之行为型模式(上)

使用Go实现23种设计模式——行为型模式(下)

访问者模式

在不改变各元素的类的前提下定义作用于这些元素的新操作

适用场景

  1. 数据结构相对稳定的对象,且需要经常在此结构上定义新操作

Go语言实现

type Number struct {
	Numbers []int
}

func (n *Number) Do(v IVisitor) {
	v.Do(n.Numbers)
}

type IVisitor interface {
	Do([]int)
}

type AddVisitor struct{}

func (v *AddVisitor) Do(numbers []int) {
	sum := 0
	for _, n := range numbers {
		sum += n
	}
	fmt.Printf("sum: %d\n", sum)
}

type TimesVisitor struct{}

func (v *TimesVisitor) Do(numbers []int) {
	res := 1
	for _, n := range numbers {
		res *= n
	}
	fmt.Printf("res: %d\n", res)
}

func main() {
	a := Number{Numbers: []int{1, 2, 3, 4}}
	a.Do(&AddVisitor{})
	a.Do(&TimesVisitor{})
}

访问者模式优点

  1. 增加新的操作简单

访问者模式缺点

  1. 增加新的数据结构困难

模板方法模式

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

适用场景

  1. 模板模式解决了一些方法通用,却在每个子类都重新写一遍的这些方法

Go语言实现

type Notify struct {
}

func (n *Notify) Send() {
	fmt.Println("send error")
}

type SMSNotify struct {
	Notify
}

func (n *SMSNotify) Send() {
	fmt.Println("send sms success")
}

type EMailNotify struct {
	Notify
}

func (n *EMailNotify) Send() {
	fmt.Println("send email success")
}

func main() {
	a := SMSNotify{}
	a.Send()

	b := EMailNotify{}
	b.Send()
}

模板方法模式优点

  1. 封装不变的部分,扩展可变部分
  2. 提取公共代码,便于维护
  3. 行为由父类控制,子类实现

模板方法模式缺点

  1. 每一个不同的实例,都需要一个子类来实现,导致类的个数增加

策略模式

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换

适用场景

  1. 一个类定义了多种行为,并且这些行为以多个if…else形式出现

Go语言实现

type Operation interface {
	Do(n1, n2 int) int
}

type OperationAdd struct {
}

func NewOperationAdd() *OperationAdd {
	return &OperationAdd{}
}

func (o *OperationAdd) Do(n1, n2 int) int {
	return n1 + n2
}

type OperationSubtract struct {
}

func NewOperationSubtract() *OperationSubtract {
	return &OperationSubtract{}
}

func (o *OperationSubtract) Do(n1, n2 int) int {
	return n1 -n2
}

type Context struct {
	operation Operation
}

func NewContext(operation Operation) *Context {
	return &Context{operation: operation}
}

func (c *Context) Do(n1, n2 int) int {
	return c.operation.Do(n1, n2)
}

func main() {
	a := NewContext(NewOperationAdd())
	a.Do(1, 2)
	b := NewContext(NewOperationSubtract())
	b.Do(3, 1)
}

策略模式优点

  1. 避免使用多重判断语句
  2. 算法可自由切换
  3. 扩展性好

策略模式缺点

  1. 客户端需要理解所有策略算法的区别,以便选择合适的算法类
  2. 策略类很多,增加维护难度

状态模式

允许一个对象在其内部状态改变时改变它的行为

适用场景

  1. 代码中包含大量与对象状态有关的条件语句

Go语言实现

type Account struct {
	Action State
	status string
}

func NewAccount(status string) *Account {
	a := &Account{status: status}
	a.initState()
	return a
}

func (a *Account) initState() {
	if a.status == "normal" {
		a.Action = &NormalState{}
	} else {
		a.Action = &BannedState{}
	}
}

type State interface {
	Login()
}

type NormalState struct{}

func (s *NormalState) Login() {
	fmt.Println("登陆成功")
}

type BannedState struct{}

func (s *BannedState) Login() {
	fmt.Println("账号封禁,禁止登陆")
}

func main() {
	a := NewAccount("normal")
	a.Action.Login()
}

状态模式优点

  1. 封装了转换规则
  2. 将所有与状态相关的行为放到一个类中,方便的增加状态
  3. 允许状态转换逻辑和状态对象合成一体,而不是巨大的条件语句块

状态模式缺点

  1. 增加了系统中类和对象的个数,导致系统运行开销变大
  2. 状态模式的结构与实现都比较复杂
  3. 对"开闭原则"的支持不友好
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请叫我雯子小姐的小爷

是雯子吖

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值