若是您以为本篇文章不错,请记获得个人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,您的支持是我最大的动力!十分感谢!