如果您觉得本篇文章不错,请记得到我的GitHub点上一个star,您的支持是我最大的动力!十分感谢!
命令模式( Command Pattern)又称为行动( Action)模式或交易( Transaction)模式。
命令模式的英文定义是:
Encapsulate a request as an object, thereby letting you parameterize clients withdifferent requests, queue or log requests, and support undoable operations.
意思是:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或,者记录请求日志,可以提供命令的撤销和恢复功能。
简单来说,命令模式就是将发送者、接收者和调用命令封装成对象,客户端调用的时候可以选择不同的对象,从而实现发送者和接收者的完全解耦。
命令模式包含如下角色:
●命令接口(Command)角色:该角色声明一一个接口,定义需要执行的命令;
●具体命令实现类( 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内部接口委托到抽象算
法层。
包含的角色罗列如下:
策略模式的优点如下:
所有策略放入一组抽象策略接口中,方便统一管理与实现;
策略模式的缺点如下:
策略模式每种策略都是单独类,策略很多时策略实现类也很可观;
客户端初始化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.
意思是:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
以生活中的例子来说,就像我们订阅报纸一样,每天有多少人订阅,当有新报纸发布的时候,就会有多少人收到新发布的报纸,这种模式就是订阅一发布模式,而报社和订阅者就满足定义中说的,一对多的依赖关系。
观察者模式包含如下角色:
抽象主题(Subject) 角色:该角色又称为“发布者”或”被观察者,可以增加和删除观察者对象;
具体主题( Concrete Subject) 角色:该角色又称为“具体发布者”或“具体被观察者”,它将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过(关联了观察关系)的观察者发出通知;
抽象观察者(Observer) 角色:该角色又称为“订阅者”,定义一个接收通知的接口,在得到主题的通知时更新自己;
具体观察者( Concrete Observer)角色:该角色又称为“ 具体订阅者”,它会实现-个接收通知的方法,用来使自身的状态与主题的状态相协调。
观察者模式的优点:
观察者和被观察者之间,实现了抽象耦合。被观察者角色所知道的只是- 个具体观察者集合,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体的观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密的耦合在一起,因此它们可以属于不同的抽象化层次,且都非常容易扩展;
此模式为广播模式,所有的观察者只需要订阅相应的主题,就能收到此主题下的所有广播。
观察者模式的缺点:
使用观察模式的典型应用场景如下:
以生活中的读者订阅为例,假设,读者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的问题,中级工程师能处理难度为1、2的问题,高级工程师能处理难度级别为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,您的支持是我最大的动力!十分感谢!