返回

4.中介者模式

定义一个接口用来封装一群对象的互动行为。中介者通过移除对象之间的引用,来减少它们之间的耦合度,并且能改变它们之间的互动独立性。

游戏系统之间的沟通

一个游戏由多个子系统共同组成,在讲外观模式的时候提到过,将这些子系统整合成一个高级界面供客户端使用,减少他们接触游戏系统的运行,并加强安全性和及减少耦合度。但内部子系统之间的沟通,又该如何处理呢?

系统越分越细,则意味着系统之间的沟通越复杂,如果系统内部持续存在着这样的连接,就会产生以下的缺点:

  • 单一系统引入太多其他的系统功能,不利于单一的系统的转换和维护
  • 单一系统被过多的系统所依赖,不利于接口的更改,容易牵一发而动全身
  • 因为需要提供给其他操作系统,系统的接口可能会过于庞大,不容易维护

引入中介者:

中介者模式

定义一个接口用来封装一群对象的互动行为。中介者通过移除对象之间的引用,来减少它们之间的耦合度,并且能改变它们之间的互动独立性。

中介者模式的定义

中介者的结构如图:

参与者的说明如下:

  • 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)
  • 数据库引擎:内部可以分成数个子系统,由专门负责数据库链接成功的功能与产生数据库操作语句的功能,两个子功能之间的沟通可以通过中介者模式来进行,让两者之间不相互依赖,方便抽换另一个子系统