游戏系统之间的沟通
一个游戏由多个子系统共同组成,在讲外观模式的时候提到过,将这些子系统整合成一个高级界面供客户端使用,减少他们接触游戏系统的运行,并加强安全性和及减少耦合度。但内部子系统之间的沟通,又该如何处理呢?
系统越分越细,则意味着系统之间的沟通越复杂,如果系统内部持续存在着这样的连接,就会产生以下的缺点:
- 单一系统引入太多其他的系统功能,不利于单一的系统的转换和维护
- 单一系统被过多的系统所依赖,不利于接口的更改,容易牵一发而动全身
- 因为需要提供给其他操作系统,系统的接口可能会过于庞大,不容易维护
引入中介者:
中介者模式
定义一个接口用来封装一群对象的互动行为。中介者通过移除对象之间的引用,来减少它们之间的耦合度,并且能改变它们之间的互动独立性。
中介者模式的定义
中介者的结构如图:
参与者的说明如下:
- Colleague(同事接口)
- 拥有一个mediator 属性成员,可以通过它来调用中介者的功能。
- ConcreteColleagueX(同事接口实现类)
- 实现Colleague 界面类,对于单一实现而言,只会依赖一个Mediator 接口。
- Mediator(中介者接口)、ConcreteMediator(中介者接口实现类)
- 由Mediator 定义让Colleague 类操作的接口。
- ConcreteMediator 实现类中包含所有 ConcreteColleague 的对象引用。
- ConcreteMediator 类之间的互动会在 ConcreteMediator 中发生。
具体实现
// 用來管理Colleague物件的介面
public abstract class Mediator
{
public abstract void SendMessage(Colleague theColleague,string Message);
}
// Mediator所控管的Colleague
public abstract class Colleague
{
protected Mediator m_Mediator = null;
public Colleague( Mediator theMediator)
{
m_Mediator = theMediator;
}
// Mediator通知請求
public abstract void Request(string Message);
}
// 實作Colleague的類別1
public class ConcreateColleague1 : Colleague
{
public ConcreateColleague1( Mediator theMediator) : base(theMediator)
{}
// 執行動作
public void Action()
{
// 執行後需要通知其它Colleageu
m_Mediator.SendMessage(this,"Colleage1發出通知");
}
// Mediator通知請求
public override void Request(string Message)
{
Debug.Log("ConcreateColleague1.Request:"+Message);
}
}
// 實作Colleague的類別2
public class ConcreateColleague2 : Colleague
{
public ConcreateColleague2( Mediator theMediator) : base(theMediator)
{}
// 執行動作
public void Action()
{
// 執行後需要通知其它Colleageu
m_Mediator.SendMessage(this,"Colleage2發出通知");
}
// Mediator通知請求
public override void Request(string Message)
{
Debug.Log("ConcreateColleague2.Request:"+Message);
}
}
// 實作Mediator界面,並集合管理Colleague物件
public class ConcreteMediator : Mediator
{
ConcreateColleague1 m_Colleague1 = null;
ConcreateColleague2 m_Colleague2 = null;
public void SetColleageu1( ConcreateColleague1 theColleague )
{
m_Colleague1 = theColleague;
}
public void SetColleageu2( ConcreateColleague2 theColleague )
{
m_Colleague2 = theColleague;
}
// 收到由Colleague通知請求
public override void SendMessage(Colleague theColleague,string Message)
{
// 收到Colleague1通知Colleague2
if( m_Colleague1 == theColleague)
m_Colleague2.Request( Message);
// 收到Colleague2通知Colleague1
if( m_Colleague2 == theColleague)
m_Colleague1.Request( Message);
}
}
因为测试程序之实现了两个子类,所以在SendMessage中只是进行简单地判断,然后就转发给另一个Colleague。但在实际应用时,Colleague 类会有许多个,必须使用别的转发方式才能提升效率。
使用中介者模式的系统架构
参与者的说明如下:
- PBaseDefenseGame:担任中介者角色,定义相关的操作界面给所有游戏系统与玩家界面来使用,并包含这些游戏系统和玩家的对象,同事负责相关的初始化流程。
- IGameSystem:游戏系统的共同父类,包含一个指向PBaseDefenseGame对象的类成员,在其下的子类都能通过这个成员向PBaseDefenseGame发出需求。
- GameEventSystem、CampSystem、……:负责游戏内的系统实现,这些系统不会相互引用及操作,必须通过PBaseDefenseGame来完成。
- IUserInterface:玩家界面的共同父类,包含一个指向PBaseDefenseGame对象的类成员,在旗下的子类都能通过这个成员向PBaseDefenseGame发出需求
- SoldierInfoUI、GampInfoUI、……:负责各玩家界面的实现,这些玩家界面与游戏系统之间不会相互引用及操作,必须通过PBaseDefenseGame来完成。
中介者模式的优点
- 不会引入太多其他的系统
- 系统被依赖的程序也降低
注意事项
中介者类会因为担任过多中介者的角色而容易出现“操作接口爆炸”的情况。因此在实现上,我们可以搭配其他的设计模式来避免发生这种情况(观察者模式)。
中介者模式的应用
- 网络引擎:连线管理系统与网络数据封包管理系统之间,如果可以通过中介者模式进行沟通,那么就能轻松地针对连线管理系统抽换所使用的通信方式(TCP或UDP)
- 数据库引擎:内部可以分成数个子系统,由专门负责数据库链接成功的功能与产生数据库操作语句的功能,两个子功能之间的沟通可以通过中介者模式来进行,让两者之间不相互依赖,方便抽换另一个子系统