Golang 设计模式(行为型)

文章目录

  • 策略模式
  • 迭代器模式
  • 访问者模式
  • 观察者模式
  • 命令模式
  • 模板方法模式
  • 责任链模式
  • 状态模式

策略模式

策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装成独立的对象,使得它们可以互相替换。在 Go 语言中,策略模式可以被广泛应用,并且具有许多优点和适用场景。

  • 场景

    1. 算法的选择需要在运行时动态确定: 当需要根据不同的条件或环境动态地选择算法时,策略模式非常有用。例如,根据用户的权限级别选择不同的身份验证策略。
    2. 需要避免使用大量的条件语句: 如果系统中存在大量的条件语句,并且它们在不同的情况下执行不同的操作,可以考虑使用策略模式来替换这些条件语句,使得代码更加清晰和易于维护。
    3. 需要实现同一种算法的多个变体: 当需要实现同一种算法的多个变体时,例如不同的排序算法或不同的文件压缩算法,策略模式可以使得这些变体可以被轻松地替换和切换。
  • 优点

    1. 灵活性: 策略模式允许在运行时动态地选择算法,而不需要修改客户端代码。这使得系统更加灵活,可以根据需要更改或添加新的算法。
    2. 可维护性: 每个算法都被封装在自己的类中,使得它们易于理解、维护和测试。当需要修改或添加新的算法时,不会影响到其他算法或客户端代码。
    3. 复用性: 策略模式提供了一种将算法独立于上下文而重用的方式。多个上下文可以共享相同的策略,从而避免了重复编码和冗余。
    4. 单一职责原则: 策略模式遵循单一职责原则,每个策略都专注于执行一个特定的任务,使得代码更加清晰、简洁和可维护。
  • 缺点

    1. 类爆炸: 如果系统中有大量的算法,并且每个算法都需要一个单独的类来实现,可能会导致类爆炸问题,使得代码结构复杂化。
    2. 客户端必须了解所有策略: 客户端必须了解所有可用的策略,以便选择合适的策略。这可能会增加客户端代码的复杂性。
  • 示例

package mainimport "fmt"// PaymentStrategy 支付策略接口
type PaymentStrategy interface {Pay(amount float64)
}// CreditCardStrategy 信用卡支付策略
type CreditCardStrategy struct{}func (c *CreditCardStrategy) Pay(amount float64) {fmt.Printf("使用信用卡支付:%.2f 元\n", amount)
}// CashStrategy 现金支付策略
type CashStrategy struct{}func (c *CashStrategy) Pay(amount float64) {fmt.Printf("使用现金支付:%.2f 元\n", amount)
}// PaymentContext 支付上下文
type PaymentContext struct {strategy PaymentStrategy
}func (p *PaymentContext) SetStrategy(strategy PaymentStrategy) {p.strategy = strategy
}func (p *PaymentContext) Pay(amount float64) {p.strategy.Pay(amount)
}func main() {// 创建支付上下文context := &PaymentContext{}// 设置信用卡支付策略并支付context.SetStrategy(&CreditCardStrategy{})context.Pay(100.50)// 设置现金支付策略并支付context.SetStrategy(&CashStrategy{})context.Pay(50.25)
}
  • 输出结果
使用信用卡支付:100.50 元
使用现金支付:50.25 元

迭代器模式

迭代器模式是一种行为型设计模式,它允许顺序访问一个聚合对象中的各个元素,而不暴露该对象的内部表示。通过迭代器模式,可以在不知道聚合对象内部结构的情况下,遍历聚合对象中的元素。

  1. 迭代器(Iterator): 定义了访问和遍历聚合对象元素的接口,包括获取下一个元素、判断是否还有元素等方法。
  2. 具体迭代器(ConcreteIterator): 实现了迭代器接口,负责遍历具体的聚合对象。
  3. 聚合对象(Aggregate): 定义了创建迭代器的接口,可以是一个集合或者容器。
  4. 具体聚合对象(ConcreteAggregate): 实现了聚合对象接口,负责创建具体的迭代器。
  • 场景

    1. 遍历聚合对象: 当需要遍历一个聚合对象中的元素,并且不希望暴露其内部表示时,可以使用迭代器模式。
    2. 统一访问方式: 当需要对不同类型的聚合对象提供统一的访问方式时,可以使用迭代器模式。通过迭代器模式,可以将不同类型的聚合对象统一成具有相同的接口。
    3. 支持多种遍历方式: 当需要支持多种不同的遍历方式时,可以使用迭代器模式。通过定义不同的迭代器,可以实现不同的遍历方式,如顺序遍历、逆序遍历等。
  • 优点

    1. 简化客户端代码: 迭代器模式将遍历聚合对象的逻辑封装在迭代器中,使得客户端不需要直接操作聚合对象,简化了客户端代码。
    2. 支持多种遍历方式: 迭代器模式可以定义多种不同的迭代器,支持不同的遍历方式,提高了灵活性。
    3. 解耦聚合对象和迭代算法: 迭代器模式将聚合对象和迭代算法解耦,使得它们可以独立变化,符合单一职责原则。
  • 缺点

    1. 增加类的个数: 迭代器模式会增加系统中类的个数,导致系统变得更加复杂。
    2. 不适合对聚合对象频繁修改: 当聚合对象频繁修改时,可能需要频繁修改迭代器,影响系统的稳定性。
  • 示例

package mainimport "fmt"// Iterator 迭代器接口
type Iterator interface {HasNext() boolNext() interface{}
}// Aggregate 聚合接口
type Aggregate interface {CreateIterator() Iterator
}// ConcreteIterator 具体迭代器
type ConcreteIterator struct {index intdata  []interface{}
}func NewConcreteIterator(data []interface{}) *ConcreteIterator {return &ConcreteIterator{index: 0,data:  data,}
}func (it *ConcreteIterator) HasNext() bool {return it.index < len(it.data)
}func (it *ConcreteIterator) Next() interface{} {if it.HasNext() {val := it.data[it.index]it.index++return val}return nil
}// ConcreteAggregate 具体聚合
type ConcreteAggregate struct {data []interface{}
}func NewConcreteAggregate() *ConcreteAggregate {return &ConcreteAggregate{data: make([]interface{}, 0),}
}func (a *ConcreteAggregate) Add(item interface{}) {a.data = append(a.data, item)
}func (a *ConcreteAggregate) CreateIterator() Iterator {return NewConcreteIterator(a.data)
}func main() {// 创建具体聚合aggregate := NewConcreteAggregate()// 添加元素aggregate.Add("元素A")aggregate.Add("元素B")aggregate.Add("元素C")// 创建具体迭代器iterator := aggregate.CreateIterator()// 遍历元素并打印中文内容for iterator.HasNext() {val := iterator.Next()fmt.Println("当前元素:", val)}
}
  • 输出结果
当前元素: 元素A
当前元素: 元素B
当前元素: 元素C

访问者模式

访问者模式是一种行为型设计模式,它允许你对一组对象的元素应用一些操作,而不暴露这些对象的内部结构。访问者模式将数据结构与数据操作分离开来,使得数据结构可以在不修改的情况下增加新的操作。

  1. 访问者(Visitor): 定义了对数据结构中各元素进行操作的方法。通过访问者模式,可以在不修改元素类的情况下添加新的操作。
  2. 元素(Element): 表示数据结构中的各个元素,通常包含一个接受访问者的方法。
  3. 具体访问者(ConcreteVisitor): 实现了访问者接口中定义的操作,对具体的元素进行具体的操作。
  4. 具体元素(ConcreteElement): 实现了元素接口中的方法,通常是访问者访问的对象。
  • 场景

    1. 数据结构稳定但操作多变: 当数据结构相对稳定,但需要经常添加新的操作时,可以使用访问者模式。访问者模式将操作封装在访问者中,从而避免了对数据结构的修改。
    2. 数据结构复杂且操作频繁变化: 当数据结构非常复杂,且操作频繁变化时,可以使用访问者模式。通过访问者模式,可以将数据结构与操作解耦,使得操作可以灵活地组合和修改。
    3. 数据结构多样化且操作分散: 当数据结构非常多样化,且各种操作分散在不同的地方时,可以使用访问者模式。访问者模式将操作统一封装在访问者中,从而避免了操作的分散性。
  • 优点

    1. 增加新操作方便: 可以通过添加新的访问者来增加新的操作,而不需要修改元素类。
    2. 提高数据结构的稳定性: 可以将不同的操作封装在访问者中,从而使得数据结构相对稳定,不容易受到外部操作的影响。
    3. 符合开闭原则: 访问者模式将操作和数据结构分离开来,使得操作可以独立地扩展,符合开闭原则。
  • 缺点

    1. 增加新元素困难: 当需要添加新的元素时,需要修改所有的访问者类,这可能会导致代码的维护困难。
    2. 破坏封装性: 访问者模式可能会破坏数据结构的封装性,因为访问者需要访问数据结构中的各个元素,可能会暴露数据结构的内部细节。
  • 示例

package mainimport "fmt"// Element 元素接口
type Element interface {Accept(visitor Visitor)
}// ConcreteElementA 具体元素A
type ConcreteElementA struct{}func (e *ConcreteElementA) Accept(visitor Visitor) {visitor.VisitConcreteElementA(e)
}// ConcreteElementB 具体元素B
type ConcreteElementB struct{}func (e *ConcreteElementB) Accept(visitor Visitor) {visitor.VisitConcreteElementB(e)
}// Visitor 访问者接口
type Visitor interface {VisitConcreteElementA(element *ConcreteElementA)VisitConcreteElementB(element *ConcreteElementB)
}// ConcreteVisitor 具体访问者
type ConcreteVisitor struct{}func (v *ConcreteVisitor) VisitConcreteElementA(element *ConcreteElementA) {fmt.Println("访问者访问具体元素A")
}func (v *ConcreteVisitor) VisitConcreteElementB(element *ConcreteElementB) {fmt.Println("访问者访问具体元素B")
}func main() {// 创建具体元素elementA := &ConcreteElementA{}elementB := &ConcreteElementB{}// 创建具体访问者visitor := &ConcreteVisitor{}// 元素接受访问者访问elementA.Accept(visitor)elementB.Accept(visitor)
}
  • 输出结果
访问者访问具体元素A
访问者访问具体元素B

观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。在 Go 中,观察者模式通常通过接口和回调函数来实现。

  • 场景

    1. GUI 开发: 在 GUI 开发中,观察者模式常用于实现用户界面和数据模型之间的同步,例如当数据模型发生变化时,通知界面更新。
    2. 事件处理: 观察者模式适用于事件驱动的系统中,被观察者可以是事件源,而观察者可以是事件处理器,当事件发生时通知观察者处理事件。
    3. 发布-订阅系统: 观察者模式也被广泛应用于发布-订阅系统中,其中被观察者充当发布者,而观察者充当订阅者,当发布者发布新消息时,通知所有订阅者。
    4. 消息队列系统: 观察者模式可以用于消息队列系统中,其中被观察者为消息队列,观察者为消息消费者,当消息队列中有新消息时,通知所有的消费者进行处理。
  • 优点

    1. 松耦合: 观察者模式将被观察者和观察者解耦,使得它们可以独立地进行修改和扩展,降低了对象之间的耦合度。
    2. 可扩展性: 由于观察者模式中被观察者和观察者之间的关系是松散的,因此可以方便地增加新的观察者或被观察者,而不会对现有代码产生影响。
    3. 通知机制: 观察者模式提供了一种灵活的通知机制,使得观察者可以及时获知被观察者的状态变化,从而采取相应的行动。
  • 缺点

    1. 过多的通知: 当被观察者的状态频繁变化时,会产生大量的通知,可能会导致性能问题。
    2. 循环依赖: 如果观察者之间存在循环依赖,可能会导致系统混乱和不稳定。
  • 示例

package mainimport "fmt"// Observer 观察者接口
type Observer interface {Update(message string)
}// Subject 主题接口
type Subject interface {RegisterObserver(observer Observer)RemoveObserver(observer Observer)NotifyObservers()
}// ConcreteObserver 具体观察者
type ConcreteObserver struct {name string
}func (o *ConcreteObserver) Update(message string) {fmt.Printf("观察者 %s 收到通知:%s\n", o.name, message)
}// ConcreteSubject 具体主题
type ConcreteSubject struct {observers []Observer
}func (s *ConcreteSubject) RegisterObserver(observer Observer) {s.observers = append(s.observers, observer)
}func (s *ConcreteSubject) RemoveObserver(observer Observer) {for i, obs := range s.observers {if obs == observer {s.observers = append(s.observers[:i], s.observers[i+1:]...)break}}
}func (s *ConcreteSubject) NotifyObservers() {message := "有新消息"for _, observer := range s.observers {observer.Update(message)}
}func main() {// 创建具体主题subject := &ConcreteSubject{}// 创建具体观察者observerA := &ConcreteObserver{name: "观察者A"}observerB := &ConcreteObserver{name: "观察者B"}// 注册观察者subject.RegisterObserver(observerA)subject.RegisterObserver(observerB)// 发送通知给观察者subject.NotifyObservers()// 移除观察者Asubject.RemoveObserver(observerA)// 再次发送通知给观察者subject.NotifyObservers()
}
  • 输出结果
观察者 观察者A 收到通知:有新消息
观察者 观察者B 收到通知:有新消息
观察者 观察者B 收到通知:有新消息

命令模式

命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使得可以用不同的请求对客户端进行参数化,并且能够支持请求的排队、记录请求日志、撤销操作等。在 Go 中,命令模式通常通过定义接口和实现类来实现。

  • 场景

    1. 菜单和工具栏操作: 命令模式可以用于实现菜单和工具栏中的各种操作,例如点击按钮执行某些操作,或者选择菜单项执行特定的命令。
    2. 撤销和重做功能: 命令模式可以用于实现撤销和重做功能,每个命令对象保存执行操作所需的所有信息,可以轻松地撤销和重做操作。
    3. 任务调度系统: 命令模式可以用于实现任务调度系统,其中命令对象表示不同的任务,调度器负责执行这些任务,并且可以对任务进行排队、调度和撤销。
    4. 日志记录系统: 命令模式可以用于实现日志记录系统,每个命令对象表示一个日志记录操作,可以保存日志记录的相关信息,并且可以将日志记录到文件或数据库中。
  • 优点

    1. 解耦请求发送者和接收者: 命令模式将请求封装成一个对象,使得请求发送者和接收者之间解耦,可以在不影响客户端的情况下修改请求的处理逻辑。
    2. 可扩展性: 新的命令可以很容易地添加到系统中,无需修改现有的客户端代码。
    3. 支持撤销和重做操作: 命令对象可以保存执行操作所需的所有信息,从而支持撤销和重做操作。
  • 缺点

    1. 类爆炸: 当命令类的数量增加时,可能会导致类的数量急剧增加,从而增加了系统的复杂性。
    2. 内存消耗: 由于每个命令对象都需要保存执行操作所需的所有信息,可能会占用大量的内存。
  • 示例

package mainimport "fmt"// Command 命令接口
type Command interface {Execute()
}// Receiver 接收者
type Receiver struct{}func (r *Receiver) Action1() {fmt.Println("接收者执行操作1")
}func (r *Receiver) Action2() {fmt.Println("接收者执行操作2")
}// ConcreteCommand1 具体命令1
type ConcreteCommand1 struct {receiver *Receiver
}func NewConcreteCommand1(receiver *Receiver) *ConcreteCommand1 {return &ConcreteCommand1{receiver: receiver}
}func (c *ConcreteCommand1) Execute() {c.receiver.Action1()
}// ConcreteCommand2 具体命令2
type ConcreteCommand2 struct {receiver *Receiver
}func NewConcreteCommand2(receiver *Receiver) *ConcreteCommand2 {return &ConcreteCommand2{receiver: receiver}
}func (c *ConcreteCommand2) Execute() {c.receiver.Action2()
}// Invoker 调用者
type Invoker struct {commands []Command
}func (i *Invoker) SetCommand(command Command) {i.commands = append(i.commands, command)
}func (i *Invoker) ExecuteCommands() {for _, command := range i.commands {command.Execute()}
}func main() {// 创建接收者receiver := &Receiver{}// 创建具体命令1和命令2并传入接收者command1 := NewConcreteCommand1(receiver)command2 := NewConcreteCommand2(receiver)// 创建调用者并设置命令invoker := &Invoker{}invoker.SetCommand(command1)invoker.SetCommand(command2)// 执行命令invoker.ExecuteCommands()
}
  • 输出结果
接收者执行操作1
接收者执行操作2

模板方法模式

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,并允许子类重写算法的特定步骤,而不改变算法的结构。模板方法模式通过将算法的通用步骤放在父类中,而将特定步骤的实现延迟到子类中,从而提高了代码的复用性和扩展性。

  • 场景

    1. 实现算法的共享: 当有多个相关的类需要实现相似的算法时,可以使用模板方法模式将算法的通用步骤放在父类中,避免代码重复。
    2. 框架设计: 模板方法模式常用于框架设计中,框架提供了一个算法的骨架,而具体的业务逻辑由子类来实现。
    3. 定义标准化接口: 模板方法模式可以定义一个标准化的接口,每个子类根据自己的需求实现接口的具体步骤,从而实现了接口的标准化。
  • 优点

    1. 代码复用: 模板方法模式将算法的通用步骤放在父类中,可以在子类中重用这些通用步骤,减少了代码的重复。
    2. 提高扩展性: 子类可以通过重写特定步骤的实现来改变算法的行为,从而提高了系统的灵活性和可扩展性。
    3. 封装不变部分: 模板方法模式将算法的不变部分封装在父类中,将可变部分交给子类来实现,降低了系统的耦合度。
  • 缺点

    1. 增加了类的数量: 模板方法模式会增加系统中类的数量,每个具体子类都需要实现特定的步骤,可能会导致类的数量急剧增加,增加了系统的复杂性。
    2. 不便于子类扩展: 如果算法的结构在父类中被固定,可能会限制子类对算法的扩展,不够灵活。
  • 示例

package mainimport "fmt"// AbstractClass 抽象类
type AbstractClass interface {TemplateMethod()PrimitiveOperation1()PrimitiveOperation2()
}// ConcreteClass 具体类
type ConcreteClass struct{}func (c *ConcreteClass) TemplateMethod() {fmt.Println("调用模板方法")c.PrimitiveOperation1()c.PrimitiveOperation2()
}func (c *ConcreteClass) PrimitiveOperation1() {fmt.Println("具体方法1的实现")
}func (c *ConcreteClass) PrimitiveOperation2() {fmt.Println("具体方法2的实现")
}func main() {// 创建具体类对象concreteClass := &ConcreteClass{}// 调用模板方法concreteClass.TemplateMethod()
}
  • 输出结果
调用模板方法
具体方法1的实现
具体方法2的实现

责任链模式

责任链模式是一种行为型设计模式,它允许多个对象都有机会处理请求,从而避免了发送者和接收者之间的耦合关系。在责任链模式中,请求沿着责任链传递,直到有一个对象处理请求为止。如果没有任何对象处理请求,请求将被忽略或者返回一个默认值。

  • 场景

    1. 请求的处理顺序不确定: 当请求的处理顺序不确定或者需要动态地确定时,可以使用责任链模式。例如,一个请求可能需要先经过权限验证,然后再经过日志记录,最后再进行业务处理。
    2. 解耦请求发送者和接收者: 当请求发送者和接收者之间的耦合关系较强,需要解耦时,可以使用责任链模式。例如,一个请求发送者可能不知道具体的接收者,而是将请求发送给责任链,直到有一个接收者处理请求为止。
    3. 多级审批流程: 责任链模式常用于多级审批流程中,每个处理器表示一个审批者,请求沿着责任链传递,直到有一个审批者处理请求为止。
  • 优点

    1. 降低耦合度: 责任链模式允许请求者和接收者之间的解耦,因为请求者不需要知道具体的接收者,而是将请求沿着责任链传递,直到有一个接收者处理请求。
    2. 灵活性和可扩展性: 责任链模式可以动态地组织处理器之间的关系,可以灵活地增加、删除或者修改处理器,从而提高了系统的灵活性和可扩展性。
    3. 单一职责原则: 责任链模式将请求的处理逻辑封装在各个处理器中,每个处理器只负责处理特定的请求,符合单一职责原则。
  • 缺点

    1. 可能导致请求被忽略: 如果责任链没有正确地设置,或者没有一个处理器能够处理请求,请求可能会被忽略或者返回一个默认值,这可能会导致系统的不稳定。
    2. 性能问题: 如果责任链过长或者处理器的数量过多,可能会导致性能问题,因为请求需要在责任链中传递多次,直到找到合适的处理器为止。
  • 示例

package mainimport "fmt"// Request 请求结构体
type Request struct {content string // 请求内容
}// Handler 处理器接口
type Handler interface {HandleRequest(request *Request)SetSuccessor(successor Handler)
}// ConcreteHandler 具体处理器
type ConcreteHandler struct {name      string  // 处理器名称successor Handler // 后继处理器
}func (c *ConcreteHandler) HandleRequest(request *Request) {if c.canHandle(request) {fmt.Printf("%s 处理请求:%s\n", c.name, request.content)} else if c.successor != nil {fmt.Printf("%s 无法处理请求,交由 %s 处理\n", c.name, c.successor.(*ConcreteHandler).name)c.successor.HandleRequest(request)} else {fmt.Printf("%s 无法处理请求\n", c.name)}
}func (c *ConcreteHandler) canHandle(request *Request) bool {// 检查处理器是否能够处理请求的逻辑// 这里简单地假设处理器名称包含请求内容的第一个字符即可处理return c.name[0] == request.content[0]
}func (c *ConcreteHandler) SetSuccessor(successor Handler) {c.successor = successor
}func main() {// 创建具体处理器handlerA := &ConcreteHandler{name: "处理器A"}handlerB := &ConcreteHandler{name: "处理器B"}handlerC := &ConcreteHandler{name: "处理器C"}// 设置责任链关系handlerA.SetSuccessor(handlerB)handlerB.SetSuccessor(handlerC)// 发送请求给责任链request1 := &Request{content: "apple"}request2 := &Request{content: "banana"}request3 := &Request{content: "carrot"}handlerA.HandleRequest(request1)handlerA.HandleRequest(request2)handlerA.HandleRequest(request3)
}
  • 输出结果
处理器A 无法处理请求,交由 处理器B 处理
处理器B 无法处理请求,交由 处理器C 处理
处理器C 无法处理请求
处理器A 无法处理请求,交由 处理器B 处理
处理器B 无法处理请求,交由 处理器C 处理
处理器C 无法处理请求
处理器A 无法处理请求,交由 处理器B 处理
处理器B 无法处理请求,交由 处理器C 处理
处理器C 无法处理请求

状态模式

状态模式是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为。状态模式将对象的行为包装在不同的状态对象中,并且允许对象在运行时根据内部状态的改变而改变其行为。这种模式使得对象在不同的状态下可以有不同的行为,而且可以动态地切换状态。

  • 场景

    1. 对象的行为取决于其状态: 当一个对象的行为取决于其内部状态,并且在运行时可以动态地改变其状态时,可以使用状态模式。例如,电梯的行为取决于其当前状态(停止、运行、故障等)。
    2. 状态之间存在转换: 当对象的状态之间存在转换,并且每个状态都有不同的行为时,可以使用状态模式。例如,交通信号灯根据不同的状态(红灯、绿灯、黄灯)展示不同的行为。
    3. 避免使用大量的条件语句: 当需要根据对象的状态执行不同的行为时,通常会使用大量的条件语句来实现,此时可以考虑使用状态模式来替换这些条件语句,使得代码更加清晰和易于维护。
  • 优点

    1. 简化条件逻辑: 状态模式通过将状态和状态相关的行为封装在状态对象中,可以简化复杂的条件逻辑,使代码更加清晰易懂。
    2. 方便扩展: 当需要增加新的状态时,只需要创建一个新的状态对象并且在上下文中进行注册,不需要修改现有的代码,符合开闭原则。
    3. 提高代码复用性: 状态模式将状态相关的行为封装在状态对象中,可以在不同的上下文中重用相同的状态对象,减少了代码的重复。
    4. 符合单一职责原则: 每个状态都封装了一组相关的行为,使得每个状态对象都具有清晰的职责,符合单一职责原则。
  • 缺点

    1. 增加类的数量: 状态模式会增加系统中类的数量,每个状态都需要一个对应的状态类,可能会导致类的数量急剧增加,增加了系统的复杂性。
    2. 状态切换的开销: 状态模式将状态和状态相关的行为封装在不同的状态对象中,当状态切换时可能会导致对象的状态转换开销增加,特别是当有大量的状态和状态转换时。
  • 示例

package mainimport "fmt"// State 状态接口
type State interface {Handle(context *Context)
}// Context 上下文
type Context struct {state State
}func (c *Context) SetState(state State) {c.state = state
}func (c *Context) Request() {c.state.Handle(c)
}// ConcreteStateA 具体状态A
type ConcreteStateA struct{}func (s *ConcreteStateA) Handle(context *Context) {fmt.Println("处理状态A")context.SetState(&ConcreteStateB{})
}// ConcreteStateB 具体状态B
type ConcreteStateB struct{}func (s *ConcreteStateB) Handle(context *Context) {fmt.Println("处理状态B")context.SetState(&ConcreteStateA{})
}func main() {// 创建上下文,并设置初始状态为状态Acontext := &Context{state: &ConcreteStateA{}}// 不断发出请求,观察状态的变化context.Request()context.Request()context.Request()context.Request()
}
  • 输出结果
处理状态A
处理状态B
处理状态A
处理状态B

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/6168.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT:输入类控件的使用

LineEdit 录入个人信息 #include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QString>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 初始化输入框ui->lineEdit…

Debian 德比安 Nginx + PHP + MySql + beanstalkd + Redis + Node.js

网卡模式选择桥接 mirrors.163.com 阿里镜像源 https://mirrors.aliyun.com/debian/ DeBian 安装软件选择时勾选上 SSH server apt update apt install sudo #安装 sudo usermod -aG sudo username #添加普通账号到 sudo 让 root 可以 SSH 配置文件 /etc/ssh/sshd_config 找…

stm32f103zet6_串口实现-DHT11-tim1(定时)

1思路 1打开时钟 1.1使用定时器实现us级的计时 1.2在打开串口 1,3在DHT11驱动中修改引脚 stm32cudeMX 配置 1打开时钟 2打开串口 3打开tim1(定时器) 4生成代码 代码设置 1导入DHT11库(tim.h是定时器的文件系统自动生成的) DHT11.c #include "dht11.h" #inc…

真香!剪映专业版VIP,解锁限制功能!

01 软件介绍 剪映专业版采用更直观更全能易用的创作面板&#xff0c;让专业剪辑变得更简单高效&#xff0c;为更多人提供畅爽的专业剪辑体验&#xff0c;让更多人享受视频创作的乐趣! 剪映专业版引入强大黑罐头素材库&#xff0c;支持搜索海量音频、表情包、贴纸、花字、特效…

TCP协议在物联网中的实战

一、TCP协议介绍 网上对TCP协议介绍众多&#xff0c;本人按照自己的理解简单介绍一下。 TCP&#xff08;Transmission Control Protocol&#xff0c; 传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输控制层通信协议。 1.1 协议机制 1.1.1 三次握手 &…

使用LwIP实现TCP Client通信(基于STM32F407)

目录 概述 1 功能介绍 1.1 代码框架 2.2 搭建系统 2 TCP Client功能实现 2.1 代码实现 2.2 具体代码 3 功能测试 3.1 测试功能描述 3.2 运行代码 测试代码下载地址&#xff1a; stm32-f407-dm9161-LwIP-tcp-client资源-CSDN文库 概述 本文主要介绍使用STM32F407和…

【多变量控制系统 Multivariable Control System】(1)DSM:术语、基本公式和MATLAB仿真【新加坡南洋理工大学】

说明&#xff1a; 题目版权归校方所有&#xff0c;仅供学习和参考使用。 DSM Control DSM Direct Synthesis Method Process Model Closed-Loop Transfer Function 基本公式 &#xff08;1&#xff09;输入、输出关系 &#xff08;2&#xff09;控制器表示 MatLab仿真…

【navicat】oracle library is not loaded 问题复现和解决方案

问题原因&#xff1a;客户端oci版本安装错误&#xff0c;navicat需要64位的oci,但是使用32位的oci。 解决方案&#xff1a;官网下载64位oci进行配置。本次演示的解决多了splplus&#xff0c;其实不必要安装也能运行。 首先判断是否数据库已经打开 尝试使用splplus连接数据库 1…

JavaScript中的Math对象方法、Date对象方法

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f31f;Math对象方法&#x1f344;1 Math静态属性&#x1f344;2 Math…

【c++】继承学习(一):继承机制与基类派生类转换

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来学习继承部分 目录 1.继承的概念和定义继承的定义继承基类成员的访问方式变化 2.基类和派生类对象赋值转换3.继承中的作用域 1.继承的概念和定义 …

Costas-Barker序列模糊函数仿真

文章目录 前言一、Costas 序列二、Barker 码三、Costas-Barker 序列模糊函数仿真1、MATLAB 核心代码2、仿真结果①、Costas-Barker 模糊函数图②、Costas-Barker 距离模糊函数图③、Costas-Barker 速度模糊函数图 四、资源自取 前言 Costas 码是一种用于载波同步的频率调制序列…

基于Ollama+AnythingLLM轻松打造本地大模型知识库

随着人工智能技术的快速发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;已成为自然语言处理领域的重要工具。然而&#xff0c;这些模型的运行通常需要大量的计算资源和复杂的部署流程。为了解决这个问题&#xff0c;Ollama应运而生&#xff0c;成为了一个高效的本地大…

学浪的缓存怎么导出来

学浪的缓存导出问题困扰着许多用户&#xff0c;备份和管理数据变得至关重要。在数字化时代&#xff0c;保护和利用数据是企业和个人不可或缺的需求。在这篇文章中&#xff0c;我们将深入探讨学浪缓存导出的方法&#xff0c;为您解决疑惑&#xff0c;让您轻松掌握数据的安全与便…

实际生产环境JVM性能优化案例分析

目录 1. 性能测试工具-Apache JMeter 1.1 JMeter的基本使用流程 2.性能优化案例 2.1 CPU占用很高排查方案 2.1.1 模拟CPU占用高的代码实现 2.1.2 通过top命令查看,可以发现PID为2100的进

237基于matlab的偏振态仿真

基于matlab的偏振态仿真&#xff0c;不同偏振态下光强计算。本仿真软件可以仿真波片对偏振光的相位调制过程。用户可以通过改变波片的类型&#xff0c;波片长轴与 X 轴的夹角&#xff0c;起偏器透光与 X 轴的夹角&#xff0c;检偏器透光轴与 X 轴的夹角等参数&#xff0c;来观察…

手写bind,apply,call

手写bind bind的传参第一个是this的新指向&#xff0c;后面传的是参数列表。bind使用后会返回一个函数&#xff0c;并且返回后的函数的this无法再改变。 用法&#xff1a;方法名.bind(this的新指向,参数1,参数2,参数3…) Function.prototype.newBind function(){const _thi…

毫米波雷达原理(含代码)(含ARS548 4D毫米波雷达数据demo和可视化视频)

毫米波雷达原理 1. 传统毫米波雷达1.1 雷达工作原理1.2 单目标距离估计1.3 单目标速度估计1.4 单目标角度估计1.5 多目标距离估计1.6 多目标速度估计1.7多目标角度估计1.7 总结 3. FMCW雷达数据处理算法4. 毫米波雷达的目标解析(含python代码)5. ARS548 4D毫米波雷达数据demo(含…

docker学习笔记3:VmWare CentOS7安装与静态ip配置

文章目录 一、安装CentOS71、下载centos镜像2、安装二、设置静态ip三、xshell连接centos本专栏的docker环境是在centos7里安装,因此首先需要会安装centos虚拟机。 本篇博客介绍如何在vm虚拟机里安装centos7。 一、安装CentOS7 1、下载centos镜像 推荐清华源,下载如下版本 …

GPU虚拟化和算力隔离探讨

1. 术语介绍 术语 全称 说明 GPU Graphics Processing Unit 显卡 CUDA Compute Unified Device Architecture 英伟达2006年推出的计算API VT/VT-x/VT-d Intel Virtualization Technology -x表示x86 CPU&#xff0c;-d表示Device SVM AMD Secure Virtual Machine …

RabbitMQ入门教学(浅入浅出)

进程间通信 互联网的通讯时网络的基础&#xff0c;一般情况下互联网的资源数据对储存在中心服务器上&#xff0c;一般情况下个体对个体的访问仅限于局域网下&#xff0c;在公网即可完成资源的访问&#xff0c;如各种网站资源&#xff0c;下载资源&#xff0c;种子等。网络通讯…