写代码都会要求高密度,低耦合,尽量避免循环引用的出现。曾经面试时,有一道面试题是这样的,如果A引用B,B引用C,C又引用A,怎么解决这种循环引用?如图:
这也是今天写这个的原因,个人思路为把环状拆分为一条直线,也就是让A持有B,B持有C,而把C要调用的A中的内容抽离出来,这里把这部分叫做D,通过B,把D传递给C。也就是C持有的,实际上不再是A,而是A里的一部分C需要的内容(D)。如图:
当然这里所给的,只是一种思路,因为根据实际问题,如果ABC三者处于同级,那再让A持有B,B持有C就不合适了,也需要只暴露某一部分公共的内容。比如玩家攻击敌人,玩家和敌人属于同级,可能只需要执行一个敌人掉血的函数,而却把整个敌人类暴露给玩家类,就很不合适了。这里不做赘述,具体要根据不同环境进一步规划该怎么写,这里只提供思路。
公共部分D,以什么形式传递,就是下面要写的内容,有两种方式,委托和接口。下面重点说接口的方式。这里提供一个别人写的博客:讲到了解决循环引用的第三种方式,反射。
https://blog.youkuaiyun.com/ZslLoveMiwa/article/details/80813568
本文只写接口方式,委托比较简单,同样可以用写一个更复杂点的事件系统去做处理。代码如下:
ClassA
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface MethodA
{
void MethodA();
}
public class ClassA : MonoBehaviour, MethodA
{
private ClassB m_claasB;
void Start () {
m_claasB = new ClassB(this);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
CCallA();
}
if (Input.GetKeyDown(KeyCode.B))
{
ACallB();
}
if (Input.GetKeyDown(KeyCode.C))
{
BCallC();
}
}
public void MethodA()
{
Debug.Log("Class A__MethodA");
}
public void CCallA()
{
m_claasB.CCallA();
}
public void BCallC()
{
m_claasB.BCallC();
}
public void ACallB()
{
m_claasB.MethodB();
}
}
ClassB:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClassB
{
private ClassC m_classC;
public ClassB(MethodA actionA)
{
m_classC=new ClassC(actionA);
}
public void MethodB()
{
Debug.Log("ClassB_MethodB");
}
public void BCallC()
{
m_classC.MethodC();
}
public void CCallA()
{
m_classC.CallA();
}
}
ClassC:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClassC : MonoBehaviour
{
private MethodA _methodA;
// Use this for initialization
public ClassC(MethodA ActionA )
{
_methodA = ActionA;
}
public void MethodC()
{
Debug.Log("ClassC _MethodC");
}
public void CallA()
{
_methodA.MethodA();
}
}
其实不管是委托,还是接口,其目的都是只暴露给其他类需要调用的部分,尽可能少的暴露不必要的内容给其他类。