mediator pattern
一.文档
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/mediator.html
二.个人理解
mediator pattern模式,翻译为中介者模式。在软件开发中,项目中可能存在很多个类,而中介者模式可以避免多个类之间的直接交互,交互交给中介来做,降低了对象之间的耦合,将对象多对多的关系变成多对一的关系,易于扩展。
应用场景:多个类之间交互频繁,存在多对多的关心
三.角色分类
mediatror 接口类,提供抽象的接口;主要提供注册、转发接口
concretemediator 具体中介类,实现注册方式、转发消息的接口 供注册方使用
colleague 同事类,抽象接口 主要提供send、receive接口 消息发送、接口;
concretemediator 具体同事类 实现send、receive接口
以现实中的租房子为例,中介公司就是 mediatror ,链家就是concretemediator ,租房者就是concretemediator ,房东也是concretemediator 。
package main
import (
"fmt"
)
const (
renterType = 1
landlordType = 2
)
type messageBox struct {
// 报价
Offer int
// 是否可以交易
Deal bool
// 角色类型
Role int
// 角色ID
ID int
}
// 抽象同事类
type colleague interface {
// 发送报价
Send()
// 接收报价 返回bool类型
// true : 接受报价
// false : 不接受报价
Receive(message messageBox) bool
// 设置中介
SetMediator(m mediator)
// 设置用户信息
SetInfo(offer, role, id int)
// 获取用户id
GetID() int
}
// 租客 具体同事类
type renter struct {
// 中介
mediator mediator
// 报价
offer int
// role
role int
// ID
id int
}
func (r *renter) Send() {
message := messageBox {
Offer : r.offer,
Role : renterType,
ID : r.id,
}
r.mediator.Relay(message)
}
func (r *renter) Receive(message messageBox) bool {
if message.Deal == false {
fmt.Printf("renter| no landlord accept the deal, consider promote the offer.\n")
return false
}
if message.Offer <= r.offer {
fmt.Printf("renter| receive offer[%d] renter's offer[%d], accept.\n", message.Offer, r.offer)
return true
} else {
fmt.Printf("renter| receive offer[%d] renter's offer[%d], no accept.\n", message.Offer, r.offer)
return false
}
}
func (r *renter) SetInfo(offer, role, id int) {
r.offer = offer
r.role = role
r.id = id
}
func (r *renter) GetID() int {
return r.id
}
func (r *renter) SetMediator(m mediator) {
r.mediator = m
}
// 租客 具体同事类
type landlord struct {
// 中介
mediator mediator
// 报价
offer int
// role
role int
// ID
id int
}
func (l *landlord) Send() {
l.mediator.Relay(messageBox{})
}
func (l *landlord) Receive(message messageBox) bool {
if message.Offer >= l.offer {
fmt.Printf("landlord| receive offer[%d] renter's offer[%d], accept.\n", message.Offer, l.offer)
return true
} else {
fmt.Printf("landlord| receive renter's offer[%d] landlord's offer[%d], no accept.\n", message.Offer, l.offer)
return false
}
}
func (l *landlord) SetInfo(offer, role, id int) {
l.offer = offer
l.role = role
l.id = id
}
func (l *landlord) GetID() int {
return l.id
}
func (l *landlord) SetMediator(m mediator) {
l.mediator = m
}
type mediator interface {
// 注册
Register(c colleague)
// 转发消息
Relay(message messageBox)
}
// 具体中介 链家
type LianJia struct {
// 租客列表
renterMap map[int]colleague
// 房东列表
landlordMap map[int]colleague
}
func (lj *LianJia) Init() {
lj.renterMap = make(map[int]colleague, 0)
lj.landlordMap = make(map[int]colleague, 0)
}
func (lj *LianJia) Register(c colleague) {
switch c.(type) {
case *renter:
lj.renterMap[c.GetID()] = c
case *landlord:
lj.landlordMap[c.GetID()] = c
default:
fmt.Printf("lianjia| unknow type, register failed")
}
}
func (lj *LianJia) Relay(message messageBox) {
switch message.Role {
case landlordType:
// 简化实现 房东不主动发送消息
fmt.Printf("lianjia| landlord don't send message")
case renterType:
for id, c := range lj.landlordMap {
if accept := c.Receive(message); accept {
renterID := message.ID
message.Deal = true
message.ID = id
lj.renterMap[renterID].Receive(message)
return
}
}
message.Deal = false
lj.renterMap[message.ID].Receive(message)
default:
fmt.Printf("lianjia| unknow role type.")
}
}
func main() {
lianjia := new(LianJia)
lianjia.Init()
landlordA := new(landlord)
landlordA.SetInfo(1000, landlordType, 1)
landlordA.SetMediator(lianjia)
lianjia.Register(landlordA)
landlordB := new(landlord)
landlordB.SetInfo(1500, landlordType, 2)
landlordB.SetMediator(lianjia)
lianjia.Register(landlordB)
renterA := new(renter)
renterA.SetInfo(800, renterType, 2)
renterA.SetMediator(lianjia)
lianjia.Register(renterA)
// 发送报价
renterA.Send()
// 提升报价 并发送
renterA.SetInfo(1200, renterType, 2)
renterA.Send()
}
memento pattern
一.文档
http://c.biancheng.net/view/1400.html
二.个人理解
memento 模式,翻译为备忘录模式。核心思想是对复杂对象的操作导致的状态变化等等希望能够进行记录保存,当对象出现不可恢复错误、主观意向等原因对对象进行恢复、回滚。又可以称为快照模式,即对对象的状态进行快照。
应用场景:游戏进度保存、数据库恢复等
三.角色分类
originator 发起者,提供设置状态、获取状态、创建快照、使用快照重新初始化的功能;被记录的对象
memento 备忘录、快照 记录originator的状态
caretaker 管理备忘录
以画画为例,画布上逐渐添加新的物体,originator为画布,mementor为单个快照,caretaker为快照管理者。
package main
import (
"fmt"
"errors"
"container/list"
)
// 快照 memento角色
type snapshot struct {
Content string
}
// 画布类 originaor角色
type drawTable struct {
// 画布中的内容
content string
}
// 作画
func (dt *drawTable) Draw(content string) {
dt.content = dt.content + content + "\n"
}
// 创建快照
func (dt *drawTable) CreateSnapshot() snapshot {
s := snapshot {
Content : dt.content,
}
return s
}
// 根据快照恢复
func (dt *drawTable) Restore(s snapshot) {
dt.content = s.Content
}
// 打印画布内容
func (dt *drawTable) Display() {
fmt.Printf("drawTable| display content[%s].\n", dt.content)
}
// 快照管理
type snapshotManager struct {
// 快照列表
// 尾部为最新 最多存储3个快照
snapshotList *list.List
}
// 初始化快照列表
func (sm *snapshotManager) Init() {
sm.snapshotList = list.New()
}
// 存储快照
// caretaker 角色
func (sm *snapshotManager) Store(s snapshot) {
if sm.snapshotList.Len() >= 3 {
sm.snapshotList.Remove(sm.snapshotList.Front())
fmt.Printf("snapshotManager| snapshot list len is over allowed, remove the front snapshot\n")
}
sm.snapshotList.PushBack(s)
}
// 选择最新快照
func (sm *snapshotManager) PickLastest() (snapshot, error) {
if sm.snapshotList.Len() == 0 {
return snapshot{}, errors.New("no snapshot")
}
return sm.snapshotList.Back().Value.(snapshot), nil
}
func main() {
drawTableA := new(drawTable)
manager := new(snapshotManager)
manager.Init()
drawTableA.Draw("a tiger")
drawTableA.Draw("a mouse")
drawTableA.Draw("a cat")
fmt.Printf("main| display first..........\n")
drawTableA.Display()
// 存储快照
manager.Store(drawTableA.CreateSnapshot())
// 继续作画
drawTableA.Draw("a pig")
drawTableA.Draw("a fruit")
fmt.Printf("main| display twice..........\n")
drawTableA.Display()
// 画的不好 恢复之前的快照
lastest, err := manager.PickLastest()
if err != nil {
fmt.Printf("main| pick lastest snapshot failed[%s].", err.Error())
return
} else {
drawTableA.Restore(lastest)
}
fmt.Printf("main| display third..........\n")
drawTableA.Display()
}
observer pattern
一.文档
http://c.biancheng.net/view/1390.html
二.个人理解
observer pattern模式,翻译为观察者模式,比较常见于发布订阅系统,多个实例对某个主题进行订阅,当该主题发生变化时候,则对已订阅的实例进行广播通知。
应用场景:发布订阅系统
三.角色分类
subject接口类,提供抽象的接口;提供注册、通知接口
concrete subject subject的实现类,实现了注册和通知接口
observer 观察者接口类,提供响应接口以接收subject的响应
concrete observer 具体的观察者类
以购物中关注为例,用户(concrete observer)订阅某个商品(concrete subject)的价格变动,当商品价格变动时则对所有订阅用户通知,用户收到价格变动后进行决策。
package main
import (
"fmt"
"container/list"
)
// observer 抽象观察者
type observer interface {
Response(price int)
}
// 具体观察者
type custom struct {
Name string
}
// 响应
func (c *custom) Response(price int) {
fmt.Printf("custom| name[%s] receive a price[%d] adjust.\n", c.Name, price)
}
// 抽象主题
type subject interface {
Register(observer)
Notify()
}
// 商品 具体主题
type commodity struct {
subscribers *list.List
price int
}
// 初始化
func (c *commodity) Init() {
c.subscribers = list.New()
}
// 调价
func (c *commodity) Adjust(price int) {
c.price = price
}
// 通知
func (c *commodity) Notify() {
for e := c.subscribers.Front(); e != nil; e = e.Next() {
e.Value.(observer).Response(c.price)
}
}
// 注册
func (c *commodity) Register(o observer) {
c.subscribers.PushBack(o)
}
func main() {
commodity := new(commodity)
commodity.Init()
customBob := new(custom)
customBob.Name = "Bob"
commodity.Register(customBob)
commodity.Adjust(100)
commodity.Notify()
customAlice := new(custom)
customAlice.Name = "Alice"
commodity.Register(customAlice)
commodity.Adjust(200)
commodity.Notify()
commodity.Adjust(300)
commodity.Notify()
}
state pattern
一.文档
https://blog.csdn.net/wwh578867817/article/details/51552358
二.个人理解
state pattern模式,翻译为状态模式,也被称为有限状态机;核心是抽象出类的所有行为,抽象出类对应的所有状态,状态类实现本状态下类的所有行为,避免繁多的if、else判断,使状态之间的实现分离、并且易于维护、扩展。
应用场景:类在不同状态下有不同的行为,状态之间可能会进行频繁转换的场景;比如tcp连接状态的维护
三.角色分类
context 上下文类,提供类的所有行为接口,管理所有状态类、提供切换状态接口
state 抽象状态类,定义类的所有行为的抽象接口
concentrete state 具体状态类,实现在某种状态下的所有行为;
例如设计手机,有开机、关机、玩这三种状态,手机上有开机、关机、玩着三种按键,phone为context类,定义开机、关机、玩着三种行为;开机状态类、关机状态类、玩状态类这三种状态类分别实现开机、关机、玩这三种行为。
package main
import (
"fmt"
)
// 状态类型
const (
TrueOnType = 1
TrueOffType = 2
PlayType = 3
)
// state抽象接口
// 定义手机的所有动作
type state interface {
// 开机
TurnOn(p *phone)
// 关机
TurnOff(p *phone)
// 玩手机
Play(p *phone)
}
// concreteState 开机状态
type TurnOnState struct {}
func (tos *TurnOnState) TurnOn(p *phone) {
fmt.Printf("TurnOnState| the phone is already turn on, no need to process.\n")
}
func (tos *TurnOnState) TurnOff(p *phone) {
fmt.Printf("TurnOnState| the phone is turn on, now turn it off.\n")
p.SetCurrentState(p.GetState(TrueOffType))
}
func (tos *TurnOnState) Play(p *phone) {
fmt.Printf("TurnOnState| the phone is turn on, now play it.\n")
p.SetCurrentState(p.GetState(PlayType))
}
// concreteState 关机状态
type TurnOffState struct {}
func (tos *TurnOffState) TurnOn(p *phone) {
fmt.Printf("TurnOffState| the phone is turn off, now turn it on.\n")
p.SetCurrentState(p.GetState(TrueOnType))
}
func (tos *TurnOffState) TurnOff(p *phone) {
fmt.Printf("TurnOffState| the phone is already turn off, no need to process.\n")
}
func (tos *TurnOffState) Play(p *phone) {
fmt.Printf("TurnOffState| the phone is turn off, can not play.\n")
}
// concreteState play状态
type PlayState struct {}
func (tos *PlayState) TurnOn(p *phone) {
fmt.Printf("PlayState| the phone is playing, no need to process.\n")
}
func (tos *PlayState) TurnOff(p *phone) {
fmt.Printf("PlayState| the phone is playing, now turn it off.\n")
p.SetCurrentState(p.GetState(TrueOffType))
}
func (tos *PlayState) Play(p *phone) {
fmt.Printf("PlayState| the phone is playing, no need to process.\n")
}
// context角色
// 手机实体类,实现所有手机功能
type phone struct {
// 当前状态
currentState state
// 各种状态
turnOn state
turnOff state
play state
}
func (p *phone) Init() {
p.turnOn = new(TurnOnState)
p.turnOff = new(TurnOffState)
p.play = new(PlayState)
p.SetCurrentState(p.turnOff)
}
func (p *phone) TurnOn() {
fmt.Printf("phone| press turn on button.\n")
p.currentState.TurnOn(p)
}
func (p *phone) TurnOff() {
fmt.Printf("phone| press turn off button.\n")
p.currentState.TurnOff(p)
}
func (p *phone) Play() {
fmt.Printf("phone| press play button.\n")
p.currentState.Play(p)
}
func (p *phone) SetCurrentState(s state) {
p.currentState = s
}
func (p *phone) GetState(stateType int) state {
switch stateType {
case TrueOnType:
return p.turnOn
case TrueOffType:
return p.turnOff
case PlayType:
return p.play
default:
return nil
}
}
func main() {
iphone := new(phone)
iphone.Init()
iphone.TurnOff()
iphone.Play()
iphone.TurnOn()
iphone.Play()
iphone.TurnOn()
iphone.TurnOff()
}
strategy pattern
一.文档
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/strategy.html
二.个人理解
strategy模式,翻译为策略模式;某项行为可能根据不同的策略进行不同的动作,完成这项动作肯能有多个路径存在,因此可以将策略抽象出来,通过设置不同的策略来执行不同的动作。
应用场景:多种算法实现的灵活切换、游戏中策略选择
三.角色分类
strategy 接口类,提供抽象的策略接口;
concrete strategy 具体实现方法类,实现strategy的各项接口;
context 上下文,可设置具体策略;
例如玩游戏中,可以选择冷酷敌人、普通敌人,根据选择的敌人种类(策略)不同,敌人就有不同的表现
package main
import (
"fmt"
)
// 策略抽象接口 提供fight功能接口
type strategy interface {
Fight()
}
// 冷酷敌人
type RuthlessStrategy struct {}
func (rs *RuthlessStrategy) Fight() {
fmt.Printf("RuthlessStrategy| use nuclear weapon.\n")
}
// 普通敌人
type NormalStrategy struct {}
func (ns *NormalStrategy) Fight() {
fmt.Printf("NormalStrategy| use normal weapon.\n")
}
// 敌人类
type Enemy struct {
s strategy
}
func (e *Enemy) SetFightStrategy(s strategy) {
e.s = s
}
func (e *Enemy) Construction() {
fmt.Printf("Enemy| construction complete.\n")
}
func (e *Enemy) Attack() {
fmt.Printf("Enemy| go to the batlefield.\n")
e.s.Fight()
}
func main() {
ruthless := new(RuthlessStrategy)
normal := new(NormalStrategy)
// 选中冷酷敌人策略
enemy := new(Enemy)
enemy.SetFightStrategy(ruthless)
enemy.Construction()
enemy.Attack()
// 选中普通敌人策略
enemy.SetFightStrategy(normal)
enemy.Construction()
enemy.Attack()
}
vistor pattern
一.文档
https://blog.csdn.net/cooldragon/article/details/52177273
二.个人理解
vistor模式,翻译为访问者模式;核心思想是 将数据的结构与行为、算法进行分离,当对数据进行操作改变、扩展时可以不修改数据结构层次。
应用场景:在数据结构较为固定,比较频繁的修改操作的场景下可以使用vistor模式
三.角色分类
element 抽象接口,提供accept方法,接收访问者
concentreate element 具体元素类,实现accept方法,调用访问者的visit方法进行数据操作
vistor 抽象接口,提供vistor方法,访问element中的数据并进行操作
concentreate vistor 具体访问者,实现具体的算法
package main
import (
"fmt"
)
// 抽象访问者
// 定义访问不同元素的接口
type vistor interface {
VistLivingRoom(e element)
VistDiningRoom(e element)
}
// 房间地图
type roomMap struct {
Length int
Wide int
}
// 抽象元素类
// 定义Accept方法
type element interface {
Accept(v vistor)
GetLivingRoomMap() roomMap
GetDiningRoomMap() roomMap
}
// concenctre vistor
// 保姆类
type nanny struct {}
// 保姆类访问客厅 获取map后 对每个点进行打扫
func (n *nanny) VistLivingRoom(e element) {
roomMap := e.GetLivingRoomMap()
for i := 0; i < roomMap.Length; i++ {
for j := 0; j < roomMap.Wide; j++ {
fmt.Printf("nanny| vist living room, clean it, coordinate x[%d] y[%d].\n", i, j)
}
}
}
// 保姆类访问餐厅 获取map后 对每个点进行打扫
func (n *nanny) VistDiningRoom(e element) {
roomMap := e.GetDiningRoomMap()
for i := 0; i < roomMap.Length; i++ {
for j := 0; j < roomMap.Wide; j++ {
fmt.Printf("nanny| vist dining room, clean it, coordinate x[%d] y[%d].\n", i, j)
}
}
}
// concenctrate vistor
// 主人类
type host struct {}
// 保姆类访问客厅 获取map后 在每个点上都进行检查卫生
func (h *host) VistLivingRoom(e element) {
roomMap := e.GetLivingRoomMap()
for i := 0; i < roomMap.Length; i++ {
for j := 0; j < roomMap.Wide; j++ {
fmt.Printf("host| vist living room, examine it, coordinate x[%d] y[%d].\n", i, j)
}
}
}
// 保姆类访问餐厅 获取map后 对每个点进行打扫
func (h *host) VistDiningRoom(e element) {
roomMap := e.GetDiningRoomMap()
for i := 0; i < roomMap.Length; i++ {
for j := 0; j < roomMap.Wide; j++ {
fmt.Printf("host| vist dining room, examine it, coordinate x[%d] y[%d].\n", i, j)
}
}
}
// concentrate element
// 房子类
type house struct {
livingRoom roomMap
diningRoom roomMap
}
func (h *house) GetDiningRoomMap() roomMap {
return h.diningRoom
}
func (h *house) GetLivingRoomMap() roomMap {
return h.livingRoom
}
func (h *house) Init() {
h.livingRoom.Length = 10
h.livingRoom.Wide = 5
h.diningRoom.Length = 7
h.diningRoom.Wide = 5
}
func (h *house) Accept(v vistor) {
v.VistDiningRoom(h)
v.VistLivingRoom(h)
}
func main() {
house := new(house)
house.Init()
nanny := new(nanny)
host := new(host)
house.Accept(nanny)
house.Accept(host)
}