gof23行为类模式(golang版)

命令模式

image

命令模式是一个高内聚的模式,其定义:将一个请求封装成一个对象,从而让你使用不同的请求客户端参数化,对请求排除或者记录请求日志,可以提供命令的撤销和恢复功能。

命令模式包含如下角色:

  • Command: 抽象命令类
    需要执行的所有命令得出在这里声明。
  • ConcreteCommand: 具体命令类
    负责实现在Command角色中定义的接口
  • Invoker: 调用者
    开始执行命令的角色,它会调用在Command角色中定义的接口。
  • Receiver: 接收者
    该角色就是干活的角色,命令传递到这里是应该被执行的

命令模式的优点

  • 类间解耦
    调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只须调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行

  • 可扩展性
    Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合

命令模式的缺点

偏偏模式的缺点就是膨胀,如果有N个命令,问题就出来了,Command的子类会有N个。

代码实现

package main

import (
    "fmt"
)

/**
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
 */

// receiver
type TV struct {
}

func (p TV) Open() {
    fmt.Println("play...")
}

func (p TV) Close() {
    fmt.Println("stop...")
}

//command
type Command interface {
    Press()
}

//ConcreteCommand
type OpenCommand struct {
    tv TV
}

func (p OpenCommand) Press() {
    p.tv.Open()
}

//ConcreteCommand
type CloseCommand struct {
    tv TV
}


func (p CloseCommand) Press() {
    p.tv.Close()
}

//invoker
type Invoke struct {
    cmd Command

}

func (p *Invoke) SetCommand(cmd Command) {
    p.cmd = cmd
}

func (p *Invoke) Do() {
    p.cmd.Press()
}

type OpenCloseCommand struct {
    index int
    cmds []Command
}


func NewOpenCLoseCommand() *OpenCloseCommand {
    openCLose := &OpenCloseCommand{}
    openCLose.cmds = make([]Command, 2)
    return openCLose
}

func (p *OpenCloseCommand) AddCommand(cmd Command) {
    p.cmds[p.index] = cmd
    p.index++
}

func (p *OpenCloseCommand) Press() {
    for _, item := range p.cmds {
        item.Press()
    }
}

func main() {
    //单一命令
    tv := TV{}
    openCommand := OpenCommand{tv}
    invoker := Invoke{openCommand}
    invoker.Do()

    closeCommand := CloseCommand{tv}
    invoker.SetCommand(closeCommand)
    invoker.Do()

    //复合命令
    fmt.Println("############复合命令###############")
    openClose := NewOpenCLoseCommand()
    openClose.AddCommand(openCommand)
    openClose.AddCommand(closeCommand)

    invoker.SetCommand(openClose)
    invoker.Do()
}

中介者模式

image

image

中介者模式的定义为:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介者模式化多对多依赖为一对多依赖。

中介者模式由以下部分组成

  • Mediator: 抽象中介者
    抽象中介者角色定义统一的接口,用于各同事角色之间的通信
  • ConcreteMediator: 具体中介者
    具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色
  • Colleague: 抽象同事类
    每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。
  • ConcreteColleague: 具体同事类
    每个同事类的行为分为两种:一种是再带本身的行为,比如改变对象本身的状态,处理自己的行为等,这种行为叫做自发行为,与其他的同事类或中介者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法。

中介者模式的优点

减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,同时也降低了类间的耦合

中介者模式的缺点

中介者会膨胀得很大,而且逻辑复杂

代码实现

package behavior

import "fmt"

/**
Mediator: 抽象中介者
ConcreteMediator: 具体中介者
Colleague: 抽象同事类
ConcreteColleague: 具体同事类
 */

//mediator 及 ConcreteMediator
type UnitedNations interface {
    ForwardMessage(message string, country Country)
}

type UnitedNationsSecurityCouncil struct {
    USA
    Iraq
}

func (unsc UnitedNationsSecurityCouncil) ForwardMessage(message string, country Country) {
    switch country.(type) {
    case USA:
        unsc.Iraq.GetMessage(message)
    case Iraq:
        unsc.USA.GetMessage(message)
    default:
        fmt.Printf("The country is not a member of UNSC")
    }
}

type Country interface {
    SendMessage(message string)
    GetMessage(message string)
}

//Colleague以及ConcreteColleague类
type USA struct {
    UnitedNations
}

func (usa USA) SendMessage(message string) {
    usa.UnitedNations.ForwardMessage(message, usa)
}

func (usa USA) GetMessage(message string) {
    fmt.Printf("美国收到对方消息: %s\n", message)
}

type Iraq struct {
    UnitedNations
}

func (iraq Iraq) SendMessage(message string) {
    iraq.UnitedNations.ForwardMessage(message, iraq)
}

func (iraq Iraq) GetMessage(message string) {
    fmt.Printf("伊拉克收到对方消息: %s\n", message)
}

client

package main

import "gof23/behavior"

func main() {
    tMediator := behavior.UnitedNationsSecurityCouncil{}
    usa := behavior.USA{tMediator}

    iraq := behavior.Iraq{tMediator}

    tMediator.USA = usa
    tMediator.Iraq = iraq

    usa.SendMessage("停止大规模杀伤性武器的研发,否则发动战争")
    iraq.SendMessage("我们没有研发大规模杀伤性武器,也不怕战争")
}

观察者模式

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

观察者模式包含如下角色:

  • Subject: 目标
    表示观察对象
  • ConcreteSubject: 具体目标
    表示具体的被观察对象。
  • Observer: 观察者
    负责接收来自Subject角色的状态变化通知
  • ConcreteObserver: 具体观察者
    表示具体的Observer
image

观察者模式的优点

  • 观察者和被观察者之间是抽象耦合
    如此设计,则不管是增加观察者还是被观察者都非常容易扩展
  • 建立一套触发机制
    根据单一职责原则每个类的职责是单一的,那么怎么把各个单一的职责串联成真实世界的复杂的逻辑关系呢?观察者模式可以完美地实现这里的链条形式

观察者模式的缺点

观察者模式需要考虑一下开发效率和运行效率问题

代码实现

package observer

import "fmt"

 //抽象观察者
type IObserver interface {
    Notify() //当被观察对象有理性的时候,触发观察者的Notify()方法
}

//具体观察者
type Observer struct {
}

func (o *Observer) Notify() {
    fmt.Println("已经触发了观察者")
}
package observer

//抽象被观察者
type ISubject interface {
    AddObservers(observers ...IObserver) //添加观察者
    NotifyObservers() //通知观察者
}

//具体被观察者
type Subject struct {
    observers []IObserver
}

func (s *Subject) AddObservers(observer ...IObserver) {
    s.observers = append(s.observers, observer...)
}

func (s *Subject) NotifyObservers() {

    for k := range s.observers {
        s.observers[k].Notify() //触发观察者
    }
}
package main

import "gof23/behavior/observer"

func main() {
    s := new(observer.Subject)
    o := new(observer.Observer)

    s.AddObservers(o)

    s.NotifyObservers()
}

状态模式

状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

状态模式包含如下角色:

  • Context: 环境类
    定义客户端需要的接口,并且负责具体状态的切换

  • State: 抽象状态类
    接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换

  • ConcreteState: 具体状态类
    每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

image

状态模式的优点

封装了转换规则。
枚举可能的状态,在枚举状态之前需要确定状态种类。
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

状态模式的缺点

状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

代码实现

package state

import "fmt"

//抽象状态角色
type State interface {
    NextState() State
    Update()
}

//具体状态角色
type GameStartState struct {
}

type GameRunState struct {
}

type GameEndState struct {
}

func (this *GameStartState) NextState() State {
    fmt.Println("Start next...")
    return new(GameRunState)
}

func (this *GameStartState) Update() {
    fmt.Println("Game start...")
}

func (this *GameRunState) NextState() State {
    fmt.Println("Run next...")
    return new(GameEndState)
}

func (this *GameRunState) Update() {
    fmt.Println("Game run...")
}

func (this *GameEndState) NextState() State {
    fmt.Println("End next...")
    return new(GameStartState)
}

func (this *GameEndState) Update() {
    fmt.Println("End")
}

client

package main

import (
    "gof23/behavior/state"
    "time"
)

//context角色
func stateMechine(state state.State, ch chan int)  {
    for  {
        select {
            case i := <-ch :
                if i == 1 {
                    state.Update()
                    state = state.NextState()
                } else if i == 0 {
                    return
                }
            default:

        }
    }
}

func main() {
    st := new(state.GameStartState)
    ch := make(chan int)

    go stateMechine(st, ch)
    time.Sleep(time.Microsecond * 3)
    ch <- 1
    time.Sleep(time.Microsecond * 3)
    ch <- 1
    time.Sleep(time.Microsecond * 3)
    ch <- 1
    time.Sleep(time.Microsecond * 3)
    ch <- 0
}

http://www.ituring.com.cn/article/200362

策略模式

策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

策略模式包含如下角色:

  • Context: 环境类
  • Strategy: 抽象策略类
  • ConcreteStrategy: 具体策略类
image

策略模式的优点

策略模式的优点

策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
策略模式提供了管理相关的算法族的办法。
策略模式提供了可以替换继承关系的办法。
使用策略模式可以避免使用多重条件转移语句。

策略模式的缺点

策略模式的缺点

客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

代码实现

package strategy

//抽象策略角色
type cashStrategy interface {
    AcceptCash(float64) float64
}

//具体策略角色
type cashNormal struct {
}

func (normal *cashNormal) AcceptCash(money float64) float64 {
    return money
}

type cashRebate struct {
    moneyRebate float64
}

func (rebate *cashRebate) AcceptCash(money float64) float64 {
    return money * rebate.moneyRebate
}

type cashReturn struct {
    moneyCondition float64
    moneyReturn float64
}

func (returned *cashReturn) AcceptCash(money float64) float64 {
    if money >= returned.moneyCondition {
        return money - float64(int(money / returned.moneyCondition)) * returned.moneyReturn
    } else {
        return money
    }
}

// context角色
type CashContext struct {
    Stratege cashStrategy
}

func NewCashContext(cashType string) *CashContext {
    c := new(CashContext)

    switch cashType {
    case "打八折":
        c.Stratege = &cashRebate{0.8}
    case "满300返100":
        c.Stratege = &cashReturn{300, 100}
    case "正常收费":
        c.Stratege = &cashNormal{}
    }
    return c
}

client

package main

import (
    "gof23/behavior/strategy"
    "fmt"
)

func main() {
    var total float64 = 0

    context := strategy.NewCashContext("满300返100")
    total += context.Stratege.AcceptCash(1 * 10000)

    context = strategy.NewCashContext("正常收费")
    total += context.Stratege.AcceptCash(1 * 10000)

    context = strategy.NewCashContext("打八折")
    total += context.Stratege.AcceptCash(1 * 10000)
    fmt.Println(total)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,741评论 0 14
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,937评论 1 15
  • javascript设计模式与开发实践 设计模式 每个设计模式我们需要从三点问题入手: 定义 作用 用法与实现 单...
    穿牛仔裤的蚊子阅读 4,055评论 0 13
  • 人生苦难重重,也是一连串的难题,面对它,你是哭哭啼啼,还是勇敢奋起,你是束手无策,还是积极的想方设法解决问题,很多...
    平凡如荷阅读 652评论 0 3
  • 刘 娜 焦点解决网络初级九期 驻马店 2018~05~27 坚持分享第92天 这个五月过得真心塞,连着三个...
    洋帆起航阅读 196评论 0 0