将两个接口合二为一

时间:2008-10-16 07:54:51

标签: c# .net oop

正如我在之前的一个问题中提到的那样,我正在重构一个我正在研究的项目。现在,一切都取决于其他一切。一切都被分成了我早期创建的名称空间,但我不认为我的分离方法非常好。我试图消除一个对象依赖于另一个对象的情况,这个对象依赖于另一个对象。

我这样做的方法是将我的项目(游戏)划分为几个程序集:

GameName.Engine
GameName.Rules
GameName.Content
GameName.Gui

GameName.Engine程序集包含许多接口,因此程序的其他部分不需要依赖任何特定的实现。例如,我有一个GameName.Engine.ICarryable接口,主要由GameName.Content.Item类(及其子类)实现。我还有一个对象允许Actor选择ICarryablePickupActionPreviously,它需要一个Item,但这暴露了不必要的方法和属性,它实际上只需要拾取和携带它所需的方法。这就是我创建ICarryable界面的原因。

现在这一切都很好,所以我的问题。 GameName.Gui应仅依赖于GameName.Engine,而不是任何实施。在GameName.Gui内,我有一个MapView对象,在其上显示Map和任何IRenderable个对象。

IRenderable基本上只是一个暴露图像和描述对象的字符串的接口。但是,MapView还需要该对象来实现ILocateable,因此它可以通过LocationChanged内的事件ILocateable查看其位置并知道它何时发生了变化。

这两个接口由ItemActor对象实现。其中,再次在GameName.Content中定义。由于它需要两个接口,我有两个选择:

  1. GameName.Gui取决于GameName.Content,并且需要Entity(基类ItemActor)。

    < / LI>
  2. GameName.Engine内创建一个如下所示的界面:

    interface ILocateableRenderable : ILocateable, IRenderable
    {
    }
    

    然后让我的ActorItem个对象实现该界面而不是单独的两个。

  3. 任何人对哪种方法最好有任何建议?是否适合创建没有方法或属性的接口,只强制实现其他两个接口?

    澄清:MapView适用于Map,它由Entity个对象组成。我不想将Entity个对象公开给MapView,只需知道它们的位置(ILocateable)以及如何渲染它们(IRenderable)。< / em>的

4 个答案:

答案 0 :(得分:2)

您似乎有两个相互矛盾的要求:

  

Inside GameName.Gui I   有一个显示的MapView对象 a   在其上映射和任何IRenderable 对象。

  

但是, MapView也需要该对象   实现ILocateable ,所以它可以   看到它的位置,知道它的时间   通过事件更改,LocationChanged,   在ILocateable内部。

因此,如果MapView只需要IRenderable,那么它应该接受IRenderable,然后检查该类是否也实现了ILocateable。在这种情况下使用它的方法。

public void Whatever(IRenderable renderable)
{
   if (renderable is ILocateable)
   {
      ((ILocateable) renderable).LocationChanged += myEventHandler;
   }

   // Do normal stuff
}

另一方面,如果你总是需要ILocateable和IRenderable,那么你应该用两种方式之一创建一个派生接口 任

interface IMappable: IRenderable, ILocateable {}

public void Whatever(IMappable mappable)
{
   mappable.LocationChanged += myEventHandler;

   // Do normal stuff
}    

interface IRenderable: ILocateable
{
  // IRenderable interface
}


public void Whatever(IRenderable renderable)
{
   renderable.LocationChanged += myEventHandler;

   // Do normal stuff
}  

取决于您的代码目前的情况。

答案 1 :(得分:2)

在所有情况下,IRenderable对象也必须实现ILocateable,所以我正在做@Sklivvz建议并从ILocateable进行IRenderable继承(这是它在讨论接口时所称的那个?):

public interface IRenderable : ILocateable
{
  // IRenderable interface
}

这种模式在.NET中使用很多。例如,ICollection接口实现IEnumerable,同时添加其他方法。这与上述代码的作用直接类比。

谢谢@Sklivvz。

答案 2 :(得分:0)

您可能会考虑什么,但我想我不是该领域的专家,是将引擎分成两部分,一个渲染器和一个位置管理器。然后,您可以将ILocateable对象添加到后者,将IRenderable对象添加到前者。但是,如果您认为这没有任何意义和/或太复杂,那么创建这个合并的界面似乎并不太糟糕。另一种选择可能是在您的引擎类中接受ILocateable和IRenderable(例如IGameObject)的超级接口,然后检查确切的类型以将对象分派到地图,位置或两者。 / p>

答案 3 :(得分:0)

选项2违反了Interface Segregation Principle。基本上,客户端不应该看到它不需要的方法......没有胖接口。如果一个对象不能只实现这些接口中的任何一个,那么你应该将它们组合成一个单独的接口。但是,如果让对象只是ILocatable而不必是IRenderable是有意义的,那么保持接口不同。我没有看到这个问题。

您可以创建一个默认基类(实现两者),以便在您发现它是常见/ 80%场景的情况下派生