若是您以爲本篇文章不錯,請記獲得個人GitHub點上一個star,您的支持是我最大的動力!十分感謝!java
命令模式( Command Pattern)又稱爲行動( Action)模式或交易( Transaction)模式。git
命令模式的英文定義是:github
Encapsulate a request as an object, thereby letting you parameterize clients withdifferent requests, queue or log requests, and support undoable operations.
意思是:將一個請求封裝成一個對象,從而讓你使用不一樣的請求把客戶端參數化,對請求排隊或,者記錄請求日誌,能夠提供命令的撤銷和恢復功能。golang
簡單來講,命令模式就是將發送者、接收者和調用命令封裝成對象,客戶端調用的時候能夠選擇不一樣的對象,從而實現發送者和接收者的徹底解耦。算法
命令模式包含以下角色:sql
●命令接口(Command)角色:該角色聲明一一個接口,定義須要執行的命令;docker
●具體命令實現類( Concrete Command) 角色:該角色定義一個接收者和行爲之間的弱耦合,實現命令方法,並調用接收者的相應操做;數據庫
●調用者(Invoker) 角色:該角色負責調用命令對象執行請求;編程
●接收者( Receiver) 角色:該角色負責具體實施和執行請求動做(方法) ;設計模式
●客戶端(Client)角色:串連執行整個流程。
命令模式的優勢:
命令模式的缺點:
命令模式的典型應用場景以下:
import "fmt" // 命令接口和實現類 type command interface { Execute() } type OpenTvCommand struct { tv *TV } func (o *OpenTvCommand) Execute() { o.tv.Open() } type CloseTvCommand struct { tv *TV } func (c *CloseTvCommand) Execute() { c.tv.Close() } type ChangeTvCommand struct { tv *TV } func (c *ChangeTvCommand) Execute() { c.tv.Change() } // 命令的接收者 type TV struct {} func (tv *TV) Open() { fmt.Println("打開電視") } func (tv *TV) Close() { fmt.Println("關閉電視") } func (tv *TV)Change() { fmt.Println("換臺") } // 命令的執行者:向TV發起命令 type TVRemote struct { open *OpenTvCommand change *ChangeTvCommand close *CloseTvCommand } func (tv *TVRemote) Open () { tv.open.Execute() } func (tv *TVRemote) Change() { tv.change.Execute() } func (tv *TVRemote) Close () { tv.close.Execute() }
// 建立接收者 rece := &TV{} // 建立命令對象 openComm := &OpenTvCommand{rece} changeComm := &ChangeTvCommand{rece} closeComm := &CloseTvCommand{rece} // 建立請求者,把命令對象設置進去 tvR := &TVRemote{ open: openComm, change: changeComm, close: closeComm, } tvR.Open() tvR.Change() tvR.Close()
打開電視 換臺 關閉電視
中介者?其實生活中你們再熟悉不過了這個詞,咱們熟悉的黃牛、房產中介等就是充當中介的角色,將咱們的買票、購房等的需求自身消化再代爲辦理。又好比說中間件,馬老師很忙,不能來,一我的有事就直接找馬老師對吧,因此要找一箇中介,客戶來了直接找中間人,中間人再和馬老師溝通,這樣馬老師和客戶那邊就是一個不可見的關係,由中介者角色進行中間協調,馬老師也能抽出更多時間去忙別的事了,解放了至關的生產力。
中介者模式( Mediator)的定義:定義一箇中介對象來封裝對象之間的交互,使原有對象之間
耦合鬆散,而且能夠獨立地改變它們之間的交互。還記得迪米特法則嗎?迪米特法則的初衷在於下降類之間的耦合,中介者模式就是迪米特法則的典型應用。
中介者模式的組成角色以下:
口;
中介者模式的優勢:
中介者模式的缺點:
中介者模式的應用場景通常比較明確,當系統有一系列對象須要相互調用,爲弱化對象間的依賴關係,使得這些對象之間鬆耦合。
生活中,最廣泛熟悉的例子就是房屋中介或者qq羣這種聊天案例,這裏咱們以房屋中介爲例,中介公司就比如咱們的中介者角色,而業主和買家就構成了兩個不一樣的同事角色,買賣雙方之間的這種交互就能夠交給中介者去對接協調:
import ( "fmt" "reflect" ) // 抽象中介公司 type MeditorCompany interface { GetSeller() Colleaguer SetSeller(seller ColleagueSeller) GetBuyer() Colleaguer SetBuyer(ColleagueBuyer) GetName() string SetName(name string) Publish(message string,colleaguer Colleaguer) } // 具體中介者 type Meditor struct { name string buyer *ColleagueBuyer seller *ColleagueSeller } func (m *Meditor) SetSeller(seller ColleagueSeller) { m.seller = &seller } func (m *Meditor) SetBuyer(b ColleagueBuyer) { m.buyer = &b } func (m *Meditor) Publish(message string, colleaguer Colleaguer) { // 若是是賣家發佈 if reflect.DeepEqual(colleaguer,m.seller){ m.buyer.Accept(message) } else if reflect.DeepEqual(colleaguer, m.buyer) { m.seller.Accept(message) } } func (m *Meditor) GetSeller() Colleaguer { return m.seller } func (m *Meditor) GetBuyer() Colleaguer { return m.buyer } func (m *Meditor) GetName() string { return m.name } func (m *Meditor) SetName(name string) { m.name = name } // 抽象同事角色 type Colleaguer interface { Colleguer(meditor MeditorCompany) Send(string) Accept(string) } // 賣家-同事角色 type ColleagueSeller struct { meditor MeditorCompany } func (c *ColleagueSeller) Send(message string) { c.meditor.Publish(message,c) } func (c *ColleagueSeller) Accept(message string) { fmt.Println("賣家收到的消息是"+message) } func (c *ColleagueSeller) Colleguer(meditor MeditorCompany) { c.meditor = meditor } // 買家-同事角色 type ColleagueBuyer struct { meditor MeditorCompany } func (c *ColleagueBuyer) Colleguer(meditor MeditorCompany) { c.meditor = meditor } func (c *ColleagueBuyer) Send(message string) { c.meditor.Publish(message,c) } func (c *ColleagueBuyer) Accept(message string) { fmt.Println("買家收到的消息是"+message) }
var ( meitdor MeditorCompany seller *ColleagueSeller buyer *ColleagueBuyer ) seller = &ColleagueSeller{meditor:meitdor} buyer = &ColleagueBuyer{meditor:meitdor} meitdor = &Meditor{ name: "58同城", buyer: buyer, seller: seller, } // 賣家和賣家註冊到中介 seller.Colleguer(meitdor) buyer.Colleguer(meitdor) // 發佈需求 seller.Send("賣一套兩室一廳100平米的Lofty") buyer.Send("求購一個兩室一廳的房子")
=== RUN TestColleagueSeller_Colleguer 買家收到的消息是賣一套兩室一廳100平米的Lofty 賣家收到的消息是求購一個兩室一廳的房子 --- PASS: TestColleagueSeller_Colleguer (0.00s) PASS
備忘錄(Memento)模式的定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,以便之後當須要時能將該對象恢復到原先保存的狀態。該模式又叫快照模式。
備忘錄模式是一種對象行爲型模式,其主要優勢以下。
其主要缺點是:資源消耗大。若是要保存的內部狀態信息過多或者特別頻繁,將會佔用比較大的內存資源。
備忘錄模式的核心是設計備忘錄類以及用於管理備忘錄的管理者類,如今咱們來學習其結構與實現。
備忘錄模式的主要角色以下。
// 備忘錄 type Memento struct { state string // 這裏就是保存的狀態 } func (m *Memento) SetState(s string) { m.state = s } func (m *Memento) GetState() string { return m.state }
// 發起人 type Originator struct { state string // 這裏就簡單一點,要保存的狀態就是一個字符串 } func (o *Originator) SetState(s string) { o.state = s } func (o *Originator) GetState() string { return o.state } // 這裏就是規定了要保存的狀態範圍 func (o *Originator) CreateMemento() *Memento { return &Memento{state: o.state} }
// 負責人 type Caretaker struct { memento *Memento } func (c *Caretaker) GetMemento() *Memento { return c.memento } func (c *Caretaker) SetMemento(m *Memento) { c.memento = m }
import "fmt" // 建立一個發起人並設置初始狀態 // 此時與備忘錄模式無關,只是模擬正常程序運行 o := &Originator{state: "hello"} fmt.Println("當前狀態:",o.GetState()) // 如今須要保存當前狀態 // 就建立一個負責人來設置(通常來講,對於一個對象的同一個備忘範圍,應當只有一個負責人,這樣方便作多狀態多備忘管理) c := new(Caretaker) c.SetMemento(o.CreateMemento()) o.SetState("world") fmt.Println("更改當前狀態:",o.GetState()) // 恢復備忘 o.SetState(c.GetMemento().GetState()) fmt.Println("恢復後狀態",o.GetState())
當前狀態: hello 更改當前狀態: world 恢復後狀態 hello
模板模式(Template Pattern )又被稱做模板方法模式( Template Method Pattern),它是一種簡單的、常見的且應用很是普遍的模式。
英文定義以下:
Define the skeleton of an algorithm in an operation, deferring some steps tosubclasses. Template Method lets subclasses redefine certain steps of analgorithm without changing the algorithm' S structure.
意思是:定義一個操做中的算法的框架,而將一些 步驟延遲到子類中。使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。簡單來講,就是爲子類設計一個模板,以便在子類中能夠複用這些方法。
模板模式包含以下角色:
模板模式的優勢:
模板模式的缺點:
模板模式的典型應用場景以下:
多個子類有公共方法,而且邏輯基本相同時;
以生活中.上班的過程爲例,咱們上班的一般流程是:起牀洗漱->通勤(開車、坐公交、打車)
->到達公司。從以上步驟能夠看出,只有通勤部分是不同的,其餘都同樣,由於開車可能會
被限號,就只能打車或坐公交去公司了,下面咱們用代碼( 模板模式)來實現一下。
// 上班抽象模板接口 type AbstractWork interface { // 因爲go是面向組合的一種思惟,從語言層不支持聚合,因此聚合須要本身把接口變量傳入來實現 GotoWork(work AbstractWork) Getup() Commute() Arrive() } // 上班抽象類 type AbsClass struct {} func (a AbsClass) GotoWork(work AbstractWork) { a.Getup() work.Commute() a.Arrive() } func (a AbsClass) Getup() { fmt.Println("1. 起牀") } func (a AbsClass) Commute() {} func (a AbsClass) Arrive() { fmt.Println("3. 到達") } type DriveToWork struct { AbsClass } func (d *DriveToWork) Commute() { fmt.Println("2. 開車去公司") } func (d *DriveToWork) GotoWork(work AbstractWork){ d.AbsClass.GotoWork(d) } type BusToWork struct { AbsClass } func (d *BusToWork) Commute() { fmt.Println("2. 坐公交去公司") } func (d *BusToWork) GotoWork(work AbstractWork) { d.AbsClass.GotoWork(d) }
var ( work AbstractWork ) work = &BusToWork{AbsClass{}} work.GotoWork(work) work = &DriveToWork{AbsClass{}} work.GotoWork(work)
=== RUN TestAbsClass_GotoWork 1. 起牀 2. 坐公交去公司 3. 到達 1. 起牀 2. 開車去公司 3. 到達 --- PASS: TestAbsClass_GotoWork (0.00s) PASS
狀態模式( Allow an object to alter its behavior when its internal state changes.Theobject will appear to
change its class.)
翻譯過來就是:容許一個對象在其內部狀態改變時改變其行爲,這個對象看起來好像是改變了其類。狀態模式是一種對象行爲型模式。
狀態模式包含角色以下:
狀態模式的優缺點總結以下:
狀態模式的應用場景以下:
首先看看不引入狀態模式時,咱們要使用多少的switch case
import "fmt" // 定義電視狀態 const ( STANDBY_STATE = 1 POWER_OFF_STATE = 2 PLAY_STATE = 3 ) type ITelevision interface { // 開機 PowerOn() // 關機 PowerOff() // 播放 Play() // 待機 Standby() } // 電視類 type Telev struct { ITelevision state int } func (telev *Telev) State() int { return telev.state } func (telev *Telev) SetState(state int) { telev.state = state } func (t *Telev) PowerOn() { switch t.state { case STANDBY_STATE: case POWER_OFF_STATE: fmt.Println("開機") t.SetState(STANDBY_STATE) case PLAY_STATE: default: } } func (t *Telev) PowerOff() { // 待機和播放狀態均可以關機 switch t.state { case STANDBY_STATE: fmt.Println("關機") t.SetState(POWER_OFF_STATE) case PLAY_STATE: fmt.Println("關機") t.SetState(POWER_OFF_STATE) case POWER_OFF_STATE: default: } } func (t *Telev) Play() { switch t.state { case STANDBY_STATE: fmt.Println("播放") t.SetState(PLAY_STATE) default: } } func (t *Telev) Standby() { switch t.state { case POWER_OFF_STATE: fmt.Println("關機") t.SetState(POWER_OFF_STATE) case PLAY_STATE: fmt.Println("待機") t.SetState(PLAY_STATE) default: } }
tv := Telev{ ITelevision: nil, state: POWER_OFF_STATE, } // 這裏由於電視仍是關機狀態,因此不會有任何的輸出 tv.Play() tv.PowerOn() tv.Play() tv.Standby() tv.PowerOff()
開機 播放 待機 關機
// 引入控制器(上下文角色) type RemoteControlMachine struct { currentSate TVState } func (r *RemoteControlMachine) PowerOn() { r.currentSate.PowerOn(r) } func (r *RemoteControlMachine) PowerOff() { r.currentSate.PowerOff(r) } func (r *RemoteControlMachine) Play() { r.currentSate.Play(r) } func (r *RemoteControlMachine) Standby() { r.currentSate.Standby(r) } func (r *RemoteControlMachine) CurrentSate() TVState { return r.currentSate } func (r *RemoteControlMachine) SetCurrentSate(currentSate TVState) { r.currentSate = currentSate } // 電視狀態抽象接口 type TVState interface { // 開機 PowerOn(r *RemoteControlMachine) // 關機 PowerOff(r *RemoteControlMachine) // 播放 Play(r *RemoteControlMachine) // 待機 Standby(r *RemoteControlMachine) } // 待機狀態 type StandByState struct { r *RemoteControlMachine } func (s *StandByState) PowerOn(r *RemoteControlMachine) {} func (s *StandByState) PowerOff(r *RemoteControlMachine) { fmt.Println("關機") // 使用遙控器設置電視機狀態爲關機 s.r = r s.r.SetCurrentSate(&PowerOffState{}) // 執行關機 s.r.PowerOff() } func (s *StandByState) Play(r *RemoteControlMachine) { fmt.Println("播放") // 使用遙控器設置電視機狀態爲播放 s.r = r s.r.SetCurrentSate(&PlayState{}) // 執行播放 s.r.Play() } func (s *StandByState) Standby(r *RemoteControlMachine) { // do nothing } // 關機狀態 type PowerOffState struct { r *RemoteControlMachine } func (s *PowerOffState) PowerOn(r *RemoteControlMachine) { fmt.Println("開機") // 使用遙控器設置電視機狀態爲開機 s.r = r s.r.SetCurrentSate(&StandByState{}) // 執行播放 s.r.Standby() } func (s *PowerOffState) PowerOff(r *RemoteControlMachine) { } func (s *PowerOffState) Play(r *RemoteControlMachine) { } func (s PowerOffState) Standby(r *RemoteControlMachine) { } // 播放狀態 type PlayState struct { r *RemoteControlMachine } func (s *PlayState) PowerOn(r *RemoteControlMachine) {} func (s *PlayState) PowerOff(r *RemoteControlMachine) { fmt.Println("關機") // 使用遙控器設置電視機狀態爲關機 s.r = r s.r.SetCurrentSate(&PowerOffState{}) // 執行關機 s.r.PowerOff() } func (s *PlayState) Play(r *RemoteControlMachine) { } func (s *PlayState) Standby(r *RemoteControlMachine) { fmt.Println("開機") // 使用遙控器設置電視機狀態爲開機 s.r = r s.r.SetCurrentSate(&StandByState{}) // 執行播放 s.r.Standby() }
context := RemoteControlMachine{} context.SetCurrentSate(&PowerOffState{}) // 若是直接播放,由於電視處於關機狀態,因此不會有輸出 context.Play() context.PowerOn() context.Play() context.Standby() context.PowerOff()
=== RUN TestTelev_Play 開機 播放 開機 關機 --- PASS: TestTelev_Play (0.00s) PASS
能夠看到,測試結果沒有任何不一樣,可是咱們沒有寫一行switch..case語句塊,反而是將對象的各個狀態抽出來作成狀態類,而後各個狀態類在對各個行爲作出實現,代碼更加精簡。
狀態模式具體的狀態類在對狀態作出變動時其行爲也跟着作出變動,其實代碼量減小並不十分明顯,可是對於狀態拓展十分友好,只須要增長狀態類再實現各個行爲便可拓展新的狀態出來,也體現了開閉原則及單一職責原則;狀態模式將對象狀態的變動放到類的內部進行,外部調用者無需關心對象的狀態及行爲的變化,也體現了更好的封裝性;另外對代碼的cpd ( 代碼重複率檢測)也是頗有提高明顯。
策略模式(Strategy Pattern: Define a family of algorithms,encapsulate each one,andmake them interchangeable.)
中文解釋爲:定義一組算法,而後將這些算法封裝起來,以便它們之間能夠互換,屬於一種對象行爲型模式。總的來講策略模式是一種比較簡單的模式,聽起來可能有點費勁,其實就是定義一組通用算法的上層接口,各個算法實現類實現該算法接口,封裝模塊使用相似於Context的概念,Context暴漏一組接口,Context內部接口委託到抽象算
法層。
包含的角色羅列以下:
策略模式的優勢以下:
策略模式的缺點以下:
策略模式的應用場景以下:
類圖:
import "fmt" type FlyBehavior interface { Fly() } type QuackBehavior interface { Quack() } type Duck struct { fly FlyBehavior quack QuackBehavior } func (d *Duck)Swim() { fmt.Println("鴨子游泳") } func (d *Duck) Display (behavior FlyBehavior,quackBehavior QuackBehavior) { behavior.Fly() quackBehavior.Quack() } type FlyWithWings struct {} func (f *FlyWithWings) Fly () { fmt.Println("鴨子用翅膀飛") } type FlyNoWay struct {} func (f *FlyNoWay) Fly () { fmt.Println("鴨子飛不起來") } type Quack struct {} func (f *Quack) Quack () { fmt.Println("鴨子嘎嘎叫") } type Squeak struct {} func (f *Squeak) Quack () { fmt.Println("鴨子咔咔叫") } type Mute struct {} func (f *Mute) Quack () { fmt.Println("鴨子不能叫") } type ReadHead struct { *Duck fly *FlyWithWings quack *Quack } func (r *ReadHead) Display () { r.Swim() r.Duck.Display(r.fly, r.quack) } type Wooden struct { *Duck fly *FlyNoWay quack *Mute } func (r *Wooden) Display () { r.Swim() r.Duck.Display(r.fly,r.quack) } type Mallard struct { *Duck fly *FlyWithWings quack *Quack } func (m *Mallard) Display () { m.Swim() m.Duck.Display(m.fly, m.quack) } type Rubber struct { *Duck fly *FlyNoWay quack *Squeak } func (r *Rubber) Display () { r.Swim() r.Duck.Display(r.fly, r.quack) }
flynoway := &FlyNoWay{} flayWihtwings := &FlyWithWings{} quack := &Quack{} sqeak := &Squeak{} mute := &Mute{} duck := ReadHead{ Duck: &Duck{}, fly: flayWihtwings, quack: quack, } duck.Display() mallard := Mallard { Duck: &Duck{}, fly: flayWihtwings, quack: quack, } mallard.Display() rub := Rubber { Duck: &Duck{}, fly: flynoway, quack: sqeak, } rub.Display() wooden := Wooden{ Duck: &Duck{}, fly: flynoway, quack: mute, } wooden.Display()
鴨子游泳 鴨子用翅膀飛 鴨子嘎嘎叫 鴨子游泳 鴨子用翅膀飛 鴨子嘎嘎叫 鴨子游泳 鴨子飛不起來 鴨子咔咔叫 鴨子游泳 鴨子飛不起來 鴨子不能叫
觀察者模式( Observer Pattern)也稱發佈閱模式。
觀察者模式的英文定義以下:
Define a one-to-many dependency between objects so that when one objectchanges state, all its dependents are notified and updated automatically.
意思是:定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則全部依賴於它的對象都會獲得通知並被自動更新。
以生活中的例子來講,就像咱們訂閱報紙同樣,天天有多少人訂閱,當有新報紙發佈的時候,就會有多少人收到新發布的報紙,這種模式就是訂閱一發布模式,而報社和訂閱者就知足定義中說的,一對多的依賴關係。
觀察者模式包含以下角色:
觀察者模式的優勢:
觀察者模式的缺點:
使用觀察模式的典型應用場景以下:
以生活中的讀者訂閱爲例,假設,讀者A和讀者B訂閱了某平臺的圖書,當有新的圖書發佈時就會給兩位讀者發送圖書,實現代碼以下。
import "fmt" // 讀者接口(訂閱接口) type IReader interface { Update(bookName string) } // 讀者類(訂閱者) type Reader struct { name string } func (r *Reader) Update(bookName string) { fmt.Println(r.name,"-收到了圖書",bookName) } // 平臺接口(發佈方接口) type IPlatform interface { Attach(reader IReader) Detach(reader IReader) NotifyObservers(bookName string) } // 具體發佈類(發佈方) type Platform struct { list []IReader } func (p *Platform) Attach(reader IReader) { // 增長讀者(訂閱者) p.list = append(p.list, reader) } func (p *Platform) Detach(reader IReader) { // 刪除讀者(訂閱者) for i,v := range p.list { if v == reader { // 刪除第i個元素,由於interface類型在golang中 // 以地址的方式傳遞,因此能夠直接比較進行刪除 // golang中只要記得byte,int,bool,string,數組,結構體,默認傳值,其餘的默認傳地址便可 p.list = append(p.list[:i],p.list[i+1:]...) } } } func (p *Platform) NotifyObservers(bookName string) { // 通知全部讀者 for _,reader := range p.list { reader.Update(bookName) } } func (p *Platform) Change (bookName string) { p.NotifyObservers(bookName) }
// 建立圖書平臺(發佈者) platform := Platform{list: []IReader{}} // 建立讀者A reader := Reader{name:"A"} // 讀者A訂閱圖書通知 platform.Attach(&reader) // 建立讀者B reader2 := Reader{name:"B"} // 讀者B訂閱圖書通知 platform.Attach(&reader2) platform.Change("《go核心編程》") // 讀者B取消訂閱 platform.Detach(&reader2) platform.Change("《go高級編程》")
A -收到了圖書 《go核心編程》 B -收到了圖書 《go核心編程》 A -收到了圖書 《go高級編程》
解釋器模式( Interpreter Pattern )提供了評估語言的語法或者表達式的方式,屬於一種行爲型的設計模式。
解釋器模式的英文原話是:
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
意思是:給定一門語言,定義它的文法的一種表示,並定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。簡單來講,就是咱們能夠定義一種語法好比就是一個表達式如: a-b+c, 起初咱們並不知道這個句子想要攜帶信息或者執行什麼操做,而後咱們要定義一個解析器來進行表達式解析,以便獲得正確的結果。
對於表達式: a-b+c 這種,咱們作個簡單的分析, a、b、c這種咱們又叫作運算參數,+、-符號這種咱們稱之爲運算符號,也就說這類表達式咱們能夠將其抽象爲兩種角色:運算參數、運算符號。運算參數通常就是英文字母,執行時各個參數須要賦上具體的數字值去替代英文字母執行,運算參數有一個共同點就是無論是a、b或者其它參數,除了被賦值以外不須要作其它任何處理,是執行時的最小單元,在解釋器模式中被稱爲終結符號。運算符號是進行運算時具體要被解釋器解釋執行的部分,想象一下,加入咱們計算機不知道如何處理相似+、-這種符號,咱們是不要針對每個符號寫一個解釋方法,以便告訴計算機該符號須要進行何種操做,這也就是解釋器模式的核心——須要完成邏輯的解釋執行操做,而運算符號在解釋器模式中也被稱爲非終結符號。
一般包含以下角色:
解釋器模式的優勢:
解釋器模式的缺點:
如今咱們以一個最簡單的例子: a+b,咱們要作的就是解釋執行這段語法文本,a和b是兩個字母也叫作兩個變量,咱們須要使用一個「+」符號來將這倆變量鏈接起來,假設咱們的語言並不知道符號"+"是什麼做用,具體做用須要咱們去實現(假設咱們並不知道+實際上是加法的意思),示例比較簡單,只是爲了說明解釋器模式沒別的意思。
import "bytes" type Context struct { text string } //抽象解釋器 type AbstractExpress interface { Interpreter(*Context) int } // 終結符,即咱們的參數構造類 type TerminalExpression struct { arg int } func (t *TerminalExpression) Interpreter(ctx *Context) int { return t.arg } // 非終結符,即咱們的運算符構造類 type NonTerminalExpression struct { left AbstractExpress right AbstractExpress } func (n NonTerminalExpression) Interpreter(ctx *Context) int { // 實現具體的a+b的解釋執行操做 if !bytes.Equal([]byte(ctx.text),[]byte("")) { return n.left.Interpreter(ctx) + n.right.Interpreter(ctx) } return 0 }
import "fmt" var ( left AbstractExpress right AbstractExpress callExpression AbstractExpress ) left = &TerminalExpression{arg:12} right = &TerminalExpression{arg:34} callExpression = &NonTerminalExpression{left:left,right:right} context := &Context{text:"+"} result := callExpression.Interpreter(context) fmt.Println(result)
46
什麼是責任鏈模式?生活中咱們常常遇到這樣的問題,好比請假審批須要層層上報處理、遇到問題各個部門甩賴扯皮,像這種,在事情沒有被處理以前,會通過一系列階段,相似於「踢皮球」似的。一樣地,當一個請求到達時,在程序沒法直接決定由哪一個對象負責處理時,客戶的請求就會造成一種鏈式傳遞,在鏈上的各個處理對象若是沒法直接決定是否由其處理時,就會將請求再傳遞至下一個鏈對象,直到請求被處理或者被丟棄等等。這種處理鏈咱們形象稱其爲「責任鏈」
責任鏈模式的定義是:使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止。
責任鏈模式的核心就是Handler鏈抽象對象,該對象包含一個指向下一個鏈對象的私有屬性,「鏈」是責任鏈的核心,就是使用該屬性進行鏈式調用實現的。責任鏈模式的包含的角色以下:
舉個例子,初級、中級、高級開發工程師分別處理問題的能力不一樣,咱們假設初級工程師只能處理難度級別爲1的問題,中級工程師能處理難度爲一、2的問題,高級工程師能處理難度級別爲一、二、3的問題,另外咱們有一個Request請求表明要處理的請求,內部包含一個難度級別和要請求的內容,咱們先來看下類圖的設計:
import "fmt" const ( DIFFICULTY_LEVEL_1 = 1 DIFFICULTY_LEVEL_2 = 2 DIFFICULTY_LEVEL_3 = 3 ) type HandleMessage func(request IRequest) type IRequest interface { // 請求級別 GetRequestLevel() int // 獲取要請求的內容 GetRequest() string } type Request struct { // 難度1--初級工程師 // 難度2--中級工程師 // 難度3--高級工程師 level int request string } func InitRequset(level int, request string) *Request { r := &Request{ level: level, request: request, } switch r.level { case 1: r.request = "難度級別1的請求是:"+ request case 2: r.request = "難度級別2的請求是:"+ request case 3: r.request = "難度級別3的請求是:"+ request } return r } func (r Request) GetRequestLevel() int { return r.level } func (r Request) GetRequest() string { return r.request } type Handler interface { HandleMessage(request IRequest) SetNextHandler(handler Handler) Response(request IRequest) GetLevel()int GetNext() Handler } // 初級工程師 type Primary struct { level int request string next Handler } func (p *Primary) GetNext() Handler { return p.next } func (p *Primary) GetLevel() int { return p.level } func (p *Primary) HandleMessage(request IRequest) { message := func(request IRequest) { // 若是請求級別小於能夠處理的級別就直接處理 if request.GetRequestLevel() <= p.GetLevel() { p.Response(request) } else { if p.GetNext() != nil { p.next.HandleMessage(request) } else { fmt.Println("---難度級別爲",request.GetRequestLevel(),"的請求沒法處理") } } } message(request) } func (p *Primary) SetNextHandler(handler Handler) { p.next = handler } func (p *Primary) Response(request IRequest) { fmt.Println("---難度級別1的請求---") fmt.Printf(request.GetRequest()) fmt.Println("初級工程師已經處理完畢") } func InitPrimary() Handler { return &Primary{ level: DIFFICULTY_LEVEL_1, request: "", } } type Middle struct { level int request string next Handler } func (p *Middle) HandleMessage(request IRequest) { message := func(request IRequest) { // 若是請求級別小於能夠處理的級別就直接處理 if request.GetRequestLevel() <= p.GetLevel() { p.Response(request) } else { if p.GetNext() != nil { p.next.HandleMessage(request) } else { fmt.Println("---難度級別爲",request.GetRequestLevel(),"的請求沒法處理") } } } message(request) } func (p *Middle) SetNextHandler(handler Handler) { p.next = handler } func (p *Middle) Response(request IRequest) { fmt.Println("---難度級別2的請求---") fmt.Printf(request.GetRequest()) fmt.Println("中級工程師已經處理完畢") } func (p *Middle) GetLevel() int { return p.level } func (p *Middle) GetNext() Handler { return p.next } type Senior struct { level int request string next Handler } func (p *Senior) HandleMessage(request IRequest) { message := func(request IRequest) { // 若是請求級別小於能夠處理的級別就直接處理 if request.GetRequestLevel() <= p.GetLevel() { p.Response(request) } else { if p.GetNext() != nil { p.next.HandleMessage(request) } else { fmt.Println("---難度級別爲",request.GetRequestLevel(),"的請求沒法處理") } } } message(request) } func (p *Senior) SetNextHandler(handler Handler) { p.next = handler } func (p *Senior) Response(request IRequest) { fmt.Println("---難度級別3的請求---") fmt.Printf(request.GetRequest()) fmt.Println("高級工程師已經處理完畢") } func (p *Senior) GetLevel() int { return p.level } func (p *Senior) GetNext() Handler { return p.next }
var ( pri Handler mid Handler sen Handler list []IRequest ) list = make([]IRequest,0) list = append(list,&Request{ level: DIFFICULTY_LEVEL_1, request: "1+1=?", }) list = append(list,&Request{ level: DIFFICULTY_LEVEL_2, request: "4*3", }) list = append(list,&Request{ level: DIFFICULTY_LEVEL_3, request: "99*99", }) list = append(list,&Request{ level: 4, request: "aaaaaaaaaaa", }) pri = InitPrimary() mid = &Middle{ level: DIFFICULTY_LEVEL_2, request: "", next: nil, } sen = &Senior{ level: DIFFICULTY_LEVEL_3, request: "", next: nil, } // 設置鏈的順序 pri.SetNextHandler(mid) mid.SetNextHandler(sen) for _,v := range list { // 責任鏈中處理該請求 pri.HandleMessage(v) }
=== RUN TestInitPrimary ---難度級別1的請求--- 1+1=?初級工程師已經處理完畢 ---難度級別2的請求--- 4*3中級工程師已經處理完畢 ---難度級別3的請求--- 99*99高級工程師已經處理完畢 ---難度級別爲 4 的請求沒法處理 --- PASS: TestInitPrimary (0.00s) PASS
迭代器模式的英文定義以下:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
意思是:提供一種方法訪問一個容器對象中各個元素,而又不需暴露該對象的內部細節。迭代器是爲容器服務的,容器是指用來容納其餘對象的對象,例如,Collection集合類型、Set類等。
迭代器模式有如下4個角色:
迭代器模式的優勢:
迭代器模式的缺點:
迭代器的應用很普遍,已經發展成爲程序開發中最基礎的工具類了。在Java語言中,從JDK1.2開始,增長了java.til.lterator 接口,並將Iterator 應用到各個彙集類( Collection)中,如ArrayList、 Vector、Stack、HashSet 等集合類都實現iterator() 方法,返回一個迭代器Iterator,用於對集合中的元素進行遍歷。這使咱們在項目中無須在獨立地寫迭代器,直接使用便可,這樣既輕鬆又便捷。
注意:要儘量地使用編程語言自身提供的迭代器,而非本身寫的迭代器。
// 抽象迭代器 type Iterator interface { Next() interface{} HasNext() bool } // 具體迭代器 type ConcreteIterator struct { index int size int con Aggregate } func (c *ConcreteIterator) HasNext() bool { return c.index < c.size } func (c *ConcreteIterator) Next() interface{} { if c.HasNext() { res := c.con.GetElement(c.index) c.index++ return res } return nil } // 抽象彙集 type Aggregate interface { Add(obj interface{}) CreateIterator() Iterator GetElement(index int) interface{} Size() int } // 具體彙集 type ConcreteAggregate struct { //私有存儲容器 docker []interface{} } func (c *ConcreteAggregate) Size() int { return len(c.docker) } func (c *ConcreteAggregate) Add(obj interface{}) { c.docker = append(c.docker,obj) } func (c *ConcreteAggregate) CreateIterator() Iterator { return &ConcreteIterator{ index: 0, size: c.Size(), con: c, } } func (c *ConcreteAggregate) GetElement(index int) interface{} { return c.docker[index] }
// 定義聚族對象 var ( aggregate Aggregate iter Iterator ) aggregate = &ConcreteAggregate{docker: []interface{}{}} aggregate.Add("java") aggregate.Add("Golang") aggregate.Add("Python") // 遍歷 iter = aggregate.CreateIterator() for iter.HasNext() { fmt.Println(iter.Next()) }
=== RUN TestConcreteAggregate_Add java Golang Python --- PASS: TestConcreteAggregate_Add (0.00s) PASS
若是您以爲本篇文章不錯,請記獲得個人GitHub點上一個star,您的支持是我最大的動力!十分感謝!