【问题标题】:Should I create interfaces for message receivers?我应该为消息接收者创建接口吗?
【发布时间】:2012-03-06 09:04:57
【问题描述】:

在我使用的游戏引擎 (Unity) 中,每个游戏对象的基类都有一个方法 'SendMessage("methodName")',它在与之关联的每个对象的每个类中调用指定的方法 - 如果它有一个。

我是否应该为可以通过这种方式发送的每条消息创建一个带有方法“methodName”的新接口,以使这种交互形式化,还是只是额外的工作而没有任何收获?这似乎是一件好事,因为这样我就可以看到这个类可以从它的声明中接收到什么消息,但是我看不到什么错误,例如,我可以帮助避免这个。而且我也没有看到它以这种方式使用 - 所以这可能只是浪费精力。

【问题讨论】:

    标签: c# interface message messaging unity3d


    【解决方案1】:

    严格的回答:是的,使用接口!现实生活中的答案:这可能取决于。 一般来说,以这种方式使用字符串是危险的(如果方法声明会改变怎么办?如果您以错误的方式键入方法名称怎么办?您有任何安全问题吗?)。这些问题的答案总是:你会在运行时而不是编译时发现这些问题(这意味着你可能会发布一些不起作用的东西,即使它是一种应该在编译时发现的错误——时间)。此外,不要忘记表演,使用必须使用反射的字符串(我猜/希望您不会有大的 switch/case 语句)。 编写接口是乏味的,但 99% 的时间是保持代码干净和易于维护的最佳方式。 也就是说,您可能需要使用该字符串来调用方法(例如,我在考虑 Java 代理或某种基于配置或消息内容的“动态”实例化)。 所以我想正确的答案是它取决于。由于速度、错误检查、维护和安全问题(如果适用),我认为您应该始终使用接口。有时您可能需要使用文本消息,但您应该谨慎使用它们,千万不要因为您会编写更少的代码(这绝不是选择一种方法而不是另一种方法的好理由)。

    附录:对于接口,您可以使用“服务守护进程”机制(例如基于 IServiceProvider)来发现所有实现特定接口的对象。使用 SendMessage() 实现同样的事情可能会很棘手(您会使用 CanHandlMessage() 方法吗?)并且由于重复而容易出错。

    示例: 这只是一个例子(解释我对“服务守护进程”的意思,请参阅函数 FindServices(),它检索实现给定接口的所有对象),我猜你不会在高速游戏中使用 LINQ 和枚举。我认为它比带有参数的 SendMessage() 更容易理解,而且它很容易更新

    interface IEnemy
    {
     Point3D Position
     {
      get;
      set;
     }
    
     void Destroy();
    }
    
    void FireBomb(Bomb bomb, Point3D impactLocation)
    {
     IEnumerable<IEnemy> affectedEnemies = 
      FindServices<IEnemy>.Where(x.Location - impactLocation <= bomb.BlastedArea);
    
     Execute(affectedEnemies, x => x.Destroy());
    }
    

    【讨论】:

    • “发现所有实现特定接口的对象”只是为了确定——我是否正确理解你在下面的回答中描述的内容与乔治基本相同? (我对他的解释更好,因为他使用了特定于引擎的功能)。
    • 是的,同样的“想法”。我将编辑答案以解释我的意思。
    【解决方案2】:

    我应该使用接口而不是接受字符串并调用函数的方法吗?

    优点:

    • 编译时安全。 (耶!)。
    • 比反射更快(配置文件以查看这是否是合法的胜利)。

    缺点:

    • 要编写更多代码。

    请随意编辑更多的优点/缺点。

    我肯定会使用所需的接口(@98​​7654321@ 或GetComponent(typeof(IInterface)) as IInterface)查找组件并以这种方式调用方法(即接口)。

    【讨论】:

    • GetComponent 方法与创建自己的消息系统基本相同吗?因为我假设内置系统是在较低级别实现的,因此应该更快。还有一个问题——为什么引擎开发人员没有这样做,而他们比我有更多的经验和知识?
    • 从某种意义上说,它是“创建自己的消息系统”(您只调用一个函数来获取组件列表,而另一个函数来实际执行该函数)。您最好在统一论坛上发布问题,也许链接到这个问题。我自己对统一并不熟悉,所以无法推测他们为什么会以他们的方式这样做或你会得到什么样的表现。
    【解决方案3】:

    如果你定义接口IGolerkaEventHandler&lt;T&gt; {bool InvokeHandler(T param);},那么你可以有一个方法HandleGolerkaEvent&lt;TT&gt;(TT param),它遍历WeakReference的列表,尝试将每个目标转换为IGolerkaEventHandler&lt;TT&gt;,并在每个上调用InvokeHandler(param)演员工作的方法。这将允许(要求)不同的“事件”类型接受不同的参数类型。将T 定义为接口中的in 参数可能有利也可能不利,具体取决于您是否希望有许多事件可以由公共代码处理某些对象但对于其他对象可能需要不同处理。

    【讨论】:

      猜你喜欢
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-20
      • 1970-01-01
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多