顾名思义,当多个对象需要互相调用对方的时候,我们可以使用一个中介对象来封装这种行为。比如班上的同学要问对方要qq号,如果是两两问对方要,就是这种网状结构。
我们建一个qq群,同学想要别人的qq号只要在群里找就好了,这就是中介者模式。
中介者模式的好处(也可能是坏处):
当我们想要改变各对象交互方式的时候,更改中介类就好了,这样降低了耦合性,使代码结构更清晰,但是一旦中介类更改,对所有用到中介类的对象都会有影响。
Unity举例:
比如我们要实现主角和npc如果距离小于10就掉血。不用中介者模式是这样写的:
public class NPC:MonoBehaviour
{
public void ReduceBlood()
{
}
public void CaculateBlood(Transform charactor)
{
float tmpDistance = Vector3.Distance (transform.position,charactor.transform.position);
if (tmpDistance < 10) {
ReduceBlood ();
}
}
}
public class Charactor:MonoBehaviour
{
public void ReduceBlood()
{
}
public void CaculateBlood(Transform NPC)
{
float tmpDistance = Vector3.Distance (transform.position,NPC.transform.position);
if (tmpDistance < 10) {
ReduceBlood ();
}
}
}
使用中介者模式:
using UnityEngine;
using System.Collections;
//中介者模式,在角色前方距离5,左右距离3米的范围内角色可以攻击
public class ActorBase:MonoBehaviour{
public virtual void ReduceBlood(){}
}
public class Character:ActorBase{
public override void ReduceBlood(){
}
}
public class Enemy:ActorBase{
public override void ReduceBlood(){
}
}
public class AttackAgent: MonoBehaviour{
/// <summary>
/// Caculates the distance.
/// </summary>
/// <param name="attacked">Attacked.</param>
/// <param name="attack">Attack.</param>
public void CaculateDistance(ActorBase attacked, ActorBase attack)
{
float tmpDistance = Vector3.Distance(attacked.transform.position, attack.transform.position);
if (tmpDistance < 10.0f) {
attacked.ReduceBlood ();
}
}
/// <summary>
/// 计算是否在攻击范围内
/// </summary>
/// <returns><c>true</c>, if attack was caculated, <c>false</c> otherwise.</returns>
/// <param name="attack">Attack.攻击者</param>
/// <param name="attacked">Attacked.被攻击者</param>
public bool CaculateAttack(GameObject attack, GameObject attacked){
//攻击者和被攻击者之间的向量,attack.transform.right即(1, 0, 0),attack.transform.forward即(0, 0, 1)
Vector3 vec = attacked.transform.position - attack.transform.position;
float rightDis = Vector3.Dot(vec, attack.transform.right.normalized);//点乘上攻击者右方向向量,也就是求出右边的距离
float leftDis = Vector3.Dot(vec, -attack.transform.right.normalized);//左边的距离
float forwordDis = Vector3.Dot(vec, attack.transform.forward.normalized);//与攻击者前方向量点乘,若小于0说明在其后方
if (rightDis<=3 && leftDis<=3 && forwordDis>=0 && forwordDis<=5){
return true;
}
return false;
}
}