文章会分成三篇,分别从创建型模式,结构型模式和行为模式三种划分,简单回顾下游戏开发的工作过程中对设计模式的使用。有纰漏之处,欢迎交流指正。
例子代码使用Golang实现,设计模式部分参考了refactoringguru.cn
行为模式:行为模式负责对象之间的高效沟通和行为委派。
1. 责任链模式
简介
将请求沿着责任链传递,链上的每个处理者都可以对请求进行处理,并传递给下一个处理者。
实现
- 声明处理者接口(handler),需要有具体的处理方法(handleFunc)和指定下一处理者的方法(setNext)
- 实现各个具体的处理子类(ConcreteHandler),每个子类处理完成后决定是返回还是把请求传递给下一个处理对象。
- 客户端可以自行组装责任链,或者从其他对象获取预先组装好的链。
游戏开发中的使用
比较典型的是对前端请求的合法性检查,例如获取道具时需要检查请求的道具ID,道具是否存在,在攻击怪物的时候需要检查技能CD情况,技能释放距离等等,这些检查的过程就能串起一个责任链。
下面是一个对添加道具进行检查的例子,分别检查了道具的Id,数量和名称合法性。
package main
import "fmt"
//处理者接口,包含处理请求的方法和设置下个处理者的方法
type progress interface {
execute(*item)
setNext(progress)
}
//检查配置处理者
type checkConfig struct {
next progress
}
func (c *checkConfig) execute(i *item) {
fmt.Println("Check item config")
if i.id <= 0 {
fmt.Println("Check item config wrong")
return
}
if c.next != nil {
c.next.execute(i)
}
}
func (c *checkConfig) setNext(next progress) {
c.next = next
}
//检查数量的处理者
type checkNum struct {
next progress
}
func (c *checkNum) execute(i *item) {
fmt.Println("Check item num")
if i.num <= 0 {
fmt.Println("Check item num wrong")
return
}
if c.next != nil {
c.next.execute(i)
}
}
func (c *checkNum) setNext(next progress) {
c.next = next
}
//检查名字的处理者
type checkName struct {
next progress
}
func (c *checkName) execute(i *item) {
fmt.Println("Check item name")
if i.name == "" {
fmt.Println("Check item name wrong")
return
}
if c.next != nil {
c.next.execute(i)
}
}
func (c *checkName) setNext(next progress) {
c.next = next
}
//道具对象
type item struct {
id int32
num int32
name string
}
func main() {
cConfig := &checkConfig{
}
cNum := &checkNum{
}
cConfig.setNext(cNum)
cName := &checkName{
}
cNum.setNext(cName)
cConfig.execute(&item{
id: 1000, num: 10, name: "abc"})
cConfig.execute(&item{
id: 1000, num: 0, name: "abc"})
}
2. 中介者模式
简介
通过创建中介者对象,可以避免多个对象之间的直接交流。例如飞机管制塔可以同时与多架飞机保持沟通,并为他们分配航道,否则每一架飞机都需要同时与其他飞机进行联系,事故率会急剧上升。
实现
- 声明中介者接口(Mediator Interface)并描述中介者和各种组件(Component)之间所需的交流接口。
- 实现中介者类。组件中保存对于中介者对象(Mediator)的引用。
- 修改组件代码,使其可以调用中介者的通知方法。然后将调用其他组件的代码放到中介者类中,并在中介者接收到该组件通知时执行这些代码。
在游戏开发中的使用
如果每一位玩家对象直接和其他玩家发送和接收消息,可能会使整个网络结构太过复杂,也缺少对聊天过程的控制。可以通过设置聊天转发对象,更好的对聊天行为进行管理。
package main
import "fmt"
//玩家接口