命令模式
命令模式是一個高內(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()
}
中介者模式
中介者模式的定義為:用一個中介對象封裝一系列的對象交互眨补,中介者使各對象不需要顯示地相互作用管削,從而使其耦合松散,而且可以獨立地改變它們之間的交互撑螺。
中介者模式化多對多依賴為一對多依賴含思。
中介者模式由以下部分組成
- 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
觀察者模式的優(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)怎静。
狀態(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
}
策略模式
策略模式(Strategy Pattern):定義一系列算法皆看,將每一個算法封裝起來,并讓它們可以相互替換背零。策略模式讓算法獨立于使用它的客戶而變化腰吟,也稱為政策模式(Policy)。
策略模式包含如下角色:
- Context: 環(huán)境類
- Strategy: 抽象策略類
- ConcreteStrategy: 具體策略類
策略模式的優(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)
}