不要在Unity中使用接口?

时间:2018-04-16 08:08:47

标签: c# unity3d

Unity中的

我使用接口。我为彼此完全不同的组件设置了逻辑。

示例:

汽车,狗和飞机将实施 var cluster = new couchbase.Cluster('couchbase://localhost'); cluster.authenticate('username', 'password'); var bucket = cluster.openBucket('database-name'); //the name of bucket bucket.on('error', function(err) { console.log('Bucket: CONNECT ERROR:', err);}); 。我可以从每个组件调用IMovable,但这些组件执行不同的代码。

Move()相同,每个组件必须将数据保存到数据库,这样可以在循环遍历所有可用的东西时保存这些东西。

问题:

论坛中的一些人说接口对Unity不利。

当销毁游戏对象并调用其界面方法时,这仍然会被执行。

不会出现错误,因为ISavable不会破坏对象。 Unity作为C ++驱动的引擎会为对象设置一个C#包装器。这些物体只会被摧毁,这是一个布尔。

被摧毁的游戏对象不会立即被摧毁,它们会在帧结束后被销毁。

直到没有到达帧的这一端,仍然可以从被破坏的对象中调用该方法。

最好的方法是仅使用抽象类,并且永远不会使用接口,因为在销毁对象时会出现不良行为。

我用一个小例子测试了这个,我创建了以下脚本:

Destroy()

执行此代码时,我得到以下结果

Test

解决方法:

我可以创建一个抽象基类并在

之间进行选择
    public interface IIntfacable
    {
        void DoSomething();

        void DestroyComponent();
    }

    public class bar : MonoBehaviour
    {
        private IIntfacable i;

        private void Start()
        {
            i = FindObjectOfType<foo>().GetComponent<IIntfacable>();
        }

        private void Update()
        {
            i.DoSomething();
            i.DestroyComponent();
            i.DoSomething();
        }
    }

    public class foo : MonoBehaviour, IIntfacable
    {
        public void DoSomething()
        {
            Debug.Log("=> DoSomething");
        }

        public void DestroyComponent()
        {
            Debug.Log("=> DestroyComponent");
            Destroy(gameObject);
        }
    }

public abstract void Foo();

但这可能会导致过度工程化。因为所有脚本都需要这个基类,无论他们是否需要这种方法。

结论:

我应该阻止使用接口吗?

1 个答案:

答案 0 :(得分:0)

我有信心说使用接口没有坏处。

潜在的恐惧是关于跟踪非托管引用,这个问题仍然存在于你使用接口,抽象类或其他什么的天气。您只需确保您的游戏代码不会尝试访问任何已Destroy()的对象。

基本上,我只是构建了一个我知道在我的场景中没有被破坏的对象集合,并在破坏后删除它们。

有回答xy-problem的风险,如果你害怕错过你的引用计数或者有一些特别不允许创建这样的列表,那么这里没有任何魔术棒,但是.net框架中有一些先例模式,IDisposable接口/模式可能会引领这种模式。

这些模式的许多实现都会检查对象的一些面向公众的方法中的标志。如果将此标志设置为true,IDisposable.Dispose()会将标志设置为true并在某个公共方法上抛出ObjectDisposedException,在这种情况下类似于MissingReferenceException。然后,某些模式将公开标志IsDisposed,以便使用该实现的其他对象可以检查而不是对对象的任何访问执行try-catch。您的模拟可能是IsDestroyed,您应该在覆盖OnDestroy

中进行设置

您可以像这样更改方法更新(它不是真的用例,为什么要在销毁它之后尝试使用它,但要表明我的观点):

    private void Update()
    {
        i.DoSomething();
        i.DestroyComponent();
        if (!i.IsDestroyed) {
           // This will not be called
           i.DoSomething();
        }
    }

并且实施可能是

public interface IIntfacable : IDestroyable
{
    void DoSomething();
}

public interface IDestroyable
{
    void DestroyComponent();
    bool IsDestroyed { get; }
}

public class foo : MonoBehaviour, IIntfacable
{
    bool IsDestroyed { get; private set; }

    public void DoSomething()
    {
        Debug.Log("=> DoSomething");
    }

    public void DestroyComponent()
    {
        Debug.Log("=> DestroyComponent");
        Destroy(gameObject);
    }

    public override OnDestroy() {
      base.OnDestroy();
      IsDestroyed = true; 
    }
}