gof23行為類模式(golang版)

命令模式

image

命令模式是一個高內(nèi)聚的模式吻氧,其定義:將一個請求封裝成一個對象带射,從而讓你使用不同的請求客戶端參數(shù)化他炊,對請求排除或者記錄請求日志霎苗,可以提供命令的撤銷和恢復功能姆吭。

命令模式包含如下角色:

  • Command: 抽象命令類
    需要執(zhí)行的所有命令得出在這里聲明。
  • ConcreteCommand: 具體命令類
    負責實現(xiàn)在Command角色中定義的接口
  • Invoker: 調(diào)用者
    開始執(zhí)行命令的角色唁盏,它會調(diào)用在Command角色中定義的接口内狸。
  • Receiver: 接收者
    該角色就是干活的角色检眯,命令傳遞到這里是應(yīng)該被執(zhí)行的

命令模式的優(yōu)點

  • 類間解耦
    調(diào)用者角色與接收者角色之間沒有任何依賴關(guān)系,調(diào)用者實現(xiàn)功能時只須調(diào)用Command抽象類的execute方法就可以昆淡,不需要了解到底是哪個接收者執(zhí)行

  • 可擴展性
    Command的子類可以非常容易地擴展锰瘸,而調(diào)用者Invoker和高層次的模塊Client不產(chǎn)生嚴重的代碼耦合

命令模式的缺點

偏偏模式的缺點就是膨脹,如果有N個命令昂灵,問題就出來了避凝,Command的子類會有N個。

代碼實現(xiàn)

package main

import (
    "fmt"
)

/**
Command: 抽象命令類
ConcreteCommand: 具體命令類
Invoker: 調(diào)用者
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: 抽象中介者
    抽象中介者角色定義統(tǒng)一的接口,用于各同事角色之間的通信
  • ConcreteMediator: 具體中介者
    具體中介者角色通過協(xié)調(diào)各同事角色實現(xiàn)協(xié)作行為实蓬,因此它必須依賴于各個同事角色
  • Colleague: 抽象同事類
    每一個同事角色都知道中介者角色茸俭,而且與其他的同事角色通信的時候,一定要通過中介者角色協(xié)作安皱。
  • ConcreteColleague: 具體同事類
    每個同事類的行為分為兩種:一種是再帶本身的行為调鬓,比如改變對象本身的狀態(tài),處理自己的行為等酌伊,這種行為叫做自發(fā)行為腾窝,與其他的同事類或中介者沒有任何的依賴;第二種是必須依賴中介者才能完成的行為居砖,叫做依賴方法虹脯。

中介者模式的優(yōu)點

減少類間的依賴,把原有的一對多的依賴變成了一對一的依賴奏候,同事類只依賴中介者循集,減少了依賴,同時也降低了類間的耦合

中介者模式的缺點

中介者會膨脹得很大蔗草,而且邏輯復雜

代碼實現(xiàn)

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("停止大規(guī)模殺傷性武器的研發(fā)咒彤,否則發(fā)動戰(zhàn)爭")
    iraq.SendMessage("我們沒有研發(fā)大規(guī)模殺傷性武器,也不怕戰(zhàn)爭")
}

觀察者模式

觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關(guān)系咒精,使得每當一個對象狀態(tài)發(fā)生改變時镶柱,其相關(guān)依賴對象皆得到通知并被自動更新。觀察者模式又叫做發(fā)布-訂閱(Publish/Subscribe)模式模叙、模型-視圖(Model/View)模式歇拆、源-監(jiān)聽器(Source/Listener)模式或從屬者(Dependents)模式。

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

  • Subject: 目標
    表示觀察對象
  • ConcreteSubject: 具體目標
    表示具體的被觀察對象。
  • Observer: 觀察者
    負責接收來自Subject角色的狀態(tài)變化通知
  • ConcreteObserver: 具體觀察者
    表示具體的Observer
image

觀察者模式的優(yōu)點

  • 觀察者和被觀察者之間是抽象耦合
    如此設(shè)計故觅,則不管是增加觀察者還是被觀察者都非常容易擴展
  • 建立一套觸發(fā)機制
    根據(jù)單一職責原則每個類的職責是單一的厂庇,那么怎么把各個單一的職責串聯(lián)成真實世界的復雜的邏輯關(guān)系呢?觀察者模式可以完美地實現(xiàn)這里的鏈條形式

觀察者模式的缺點

觀察者模式需要考慮一下開發(fā)效率和運行效率問題

代碼實現(xiàn)

package observer

import "fmt"

 //抽象觀察者
type IObserver interface {
    Notify() //當被觀察對象有理性的時候输吏,觸發(fā)觀察者的Notify()方法
}

//具體觀察者
type Observer struct {
}

func (o *Observer) Notify() {
    fmt.Println("已經(jīng)觸發(fā)了觀察者")
}
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() //觸發(fā)觀察者
    }
}
package main

import "gof23/behavior/observer"

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

    s.AddObservers(o)

    s.NotifyObservers()
}

狀態(tài)模式

狀態(tài)模式(State Pattern) :允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為宋列,對象看起來似乎修改了它的類。其別名為狀態(tài)對象(Objects for States)评也,狀態(tài)模式是一種對象行為型模式。

狀態(tài)模式包含如下角色:

  • Context: 環(huán)境類
    定義客戶端需要的接口灭返,并且負責具體狀態(tài)的切換

  • State: 抽象狀態(tài)類
    接口或抽象類盗迟,負責對象狀態(tài)定義,并且封裝環(huán)境角色以實現(xiàn)狀態(tài)切換

  • ConcreteState: 具體狀態(tài)類
    每一個具體狀態(tài)必須完成兩個職責:本狀態(tài)的行為管理以及趨向狀態(tài)處理熙含,通俗地說罚缕,就是本狀態(tài)下要做的事情,以及本狀態(tài)如何過渡到其他狀態(tài)怎静。

image

狀態(tài)模式的優(yōu)點

封裝了轉(zhuǎn)換規(guī)則邮弹。
枚舉可能的狀態(tài),在枚舉狀態(tài)之前需要確定狀態(tài)種類蚓聘。
將所有與某個狀態(tài)有關(guān)的行為放到一個類中腌乡,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為夜牡。
允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體与纽,而不是某一個巨大的條件語句塊。
可以讓多個環(huán)境對象共享一個狀態(tài)對象塘装,從而減少系統(tǒng)中對象的個數(shù)急迂。

狀態(tài)模式的缺點

狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)。
狀態(tài)模式的結(jié)構(gòu)與實現(xiàn)都較為復雜蹦肴,如果使用不當將導致程序結(jié)構(gòu)和代碼的混亂僚碎。
狀態(tài)模式對“開閉原則”的支持并不太好,對于可以切換狀態(tài)的狀態(tài)模式阴幌,增加新的狀態(tài)類需要修改那些負責狀態(tài)轉(zhuǎn)換的源代碼勺阐,否則無法切換到新增狀態(tài);而且修改某個狀態(tài)類的行為也需修改對應(yīng)類的源代碼裂七。

代碼實現(xiàn)

package state

import "fmt"

//抽象狀態(tài)角色
type State interface {
    NextState() State
    Update()
}

//具體狀態(tài)角色
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: 環(huán)境類
  • Strategy: 抽象策略類
  • ConcreteStrategy: 具體策略類
image

策略模式的優(yōu)點

策略模式的優(yōu)點

策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇算法或行為毛雇,也可以靈活地增加新的算法或行為嫉称。
策略模式提供了管理相關(guān)的算法族的辦法。
策略模式提供了可以替換繼承關(guān)系的辦法灵疮。
使用策略模式可以避免使用多重條件轉(zhuǎn)移語句织阅。

策略模式的缺點

策略模式的缺點

客戶端必須知道所有的策略類,并自行決定使用哪一個策略類震捣。
策略模式將造成產(chǎn)生很多策略類荔棉,可以通過使用享元模式在一定程度上減少對象的數(shù)量。

代碼實現(xiàn)

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)
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒿赢,一起剝皮案震驚了整個濱河市润樱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羡棵,老刑警劉巖壹若,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異皂冰,居然都是意外死亡店展,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門秃流,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赂蕴,“玉大人,你說我怎么就攤上這事剔应∷龋” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵峻贮,是天一觀的道長席怪。 經(jīng)常有香客問我,道長纤控,這世上最難降的妖魔是什么挂捻? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮船万,結(jié)果婚禮上刻撒,老公的妹妹穿的比我還像新娘。我一直安慰自己耿导,他們只是感情好声怔,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舱呻,像睡著了一般醋火。 火紅的嫁衣襯著肌膚如雪悠汽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天芥驳,我揣著相機與錄音柿冲,去河邊找鬼。 笑死兆旬,一個胖子當著我的面吹牛假抄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丽猬,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼宿饱,長吁一口氣:“原來是場噩夢啊……” “哼坪蚁!你這毒婦竟也來了蛤高?” 一聲冷哼從身側(cè)響起朴读,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤荒吏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后突勇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年沥寥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柠座。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡邑雅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妈经,到底是詐尸還是另有隱情淮野,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布吹泡,位于F島的核電站骤星,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏爆哑。R本人自食惡果不足惜洞难,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揭朝。 院中可真熱鬧队贱,春花似錦、人聲如沸潭袱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屯换。三九已至编丘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘪吏。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工癣防, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掌眠。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓蕾盯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蓝丙。 傳聞我的和親對象是個殘疾皇子级遭,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計模式概述 在學習面向?qū)ο笃叽笤O(shè)計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上渺尘,這兩者...
    彥幀閱讀 3,734評論 0 14
  • 設(shè)計模式匯總 一挫鸽、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,903評論 1 15
  • javascript設(shè)計模式與開發(fā)實踐 設(shè)計模式 每個設(shè)計模式我們需要從三點問題入手: 定義 作用 用法與實現(xiàn) 單...
    穿牛仔褲的蚊子閱讀 4,036評論 0 13
  • 人生苦難重重,也是一連串的難題医咨,面對它枫匾,你是哭哭啼啼,還是勇敢奮起拟淮,你是束手無策干茉,還是積極的想方設(shè)法解決問題,很多...
    平凡如荷閱讀 642評論 0 3
  • 劉 娜 焦點解決網(wǎng)絡(luò)初級九期 駐馬店 2018~05~27 堅持分享第92天 這個五月過得真心塞很泊,連著三個...
    洋帆起航閱讀 193評論 0 0