tags:

views:

201

answers:

4

As I mention in an earlier question, I'm refactoring a project I'm working on. Right now, everything depends on everything else. Everything is separated into namespaces I created early on, but I don't think my method of separtion was very good. I'm trying to eliminate cases where an object depends on another object in a different namespace that depends on the other object.

The way I'm doing this, is by partitioning my project (a game) into a few assemblies:

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

The GameName.Engine assembly contains a bunch of interfaces, so other parts of the program don't need to depend on any particular implementation. For instance, I have a GameName.Engine.ICarryable interface that is primarily implemented by GameName.Content.Item class (and its sub-classes). I also have an object to allow an Actor to pickup an ICarryable; PickupAction. Previously, it required an Item, but this exposes unneccessary methods and properties, where it really only needed the methods required to pick it up and carry it. That's why I've created the ICarryable interface.

Now that's all good, so to my question. GameName.Gui should only depend on GameName.Engine, not any implementation. Inside GameName.Gui I have a MapView object that displays a Map and any IRenderable objects on it.

IRenderable is basically just an interface that exposes an image and some strings describing the object. But, the MapView also needs the object to implement ILocateable, so it can see its location and know when its changed via an event, LocationChanged, inside ILocateable.

These two interfaces are implemented by both Item and Actor objects. Which, again are defined in GameName.Content. Since it needs both interfaces, I have two choices:

  1. Make GameName.Gui depend on GameName.Content and require an Entity (base-class of Item and Actor).
  2. Make an interface inside GameName.Engine that looks like this:

    interface ILocateableRenderable : ILocateable, IRenderable { }

And then make my Actor and Item objects implement that interface instead of the two individually.

Anyone have any suggestions on which method is the best? Is it appropriate to create an interface with no methods or properties, that only enforces implementing two other interfaces?

Clarification: MapView works on a Map, which is composed of Entity objects. I don't want to expose the Entity objects to the MapView, it only needs to know their location (ILocateable) and how to render them (IRenderable).

A: 

What you might consider, but I guess I am no expert in the area, is to split the engine in two, a renderer and a location-manager. You could then add ILocateable objects to the latter and IRenderable ones to the former. However if you think this doesn't make any sense and/or is far too complex, creating this merged interface doesn't seem too bad. Another option might be to add a super-interface to both ILocateable and IRenderable, for example IGameObject, that you would accept in your engine class, and then check the exact type to dispatch objects to the map, the location-thing or both.

Seldaek
+2  A: 

You seem to have two conflicting requirements:

Inside GameName.Gui I have a MapView object that displays a Map and any IRenderable objects on it.

and

But, the MapView also needs the object to implement ILocateable, so it can see its location and know when its changed via an event, LocationChanged, inside ILocateable.

So, if the MapView only needs IRenderable, then it should accept IRenderable and then check whether the class also implements ILocateable. In this case use its methods.

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

   // Do normal stuff
}

On the other hand, if you always need it to be ILocateable and IRenderable, then you should really create a derived interface in one of two ways Either

interface IMappable: IRenderable, ILocateable {}

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

   // Do normal stuff
}

or

interface IRenderable: ILocateable
{
  // IRenderable interface
}


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

   // Do normal stuff
}

depending on how your code is at the moment.

Sklivvz
Hmm, I didn't think about making IRenderable implement ILocateable. Thinking about it, it doesn't make since to have an IRenderable that is not ILocateable, because if you the MapView doesn't know where it is, it definitely can't render it.
Mark A. Nicolosi
A: 

Option 2 violates the Interface Segregation Principle. Basically a client should not have to see methods that it doesn't need... no fat interfaces. If an object cannot just implement any one of those Interfaces, then you should combine them to be a single interface. However if it makes sense to have an object just be ILocatable without it having to be a IRenderable, keep the interfaces distinct. I don't see a problem with that.

You can create a default base class (implementing both) to derive from in case you find that to be the common/80% scenario

Gishu
Tell that to System.Windows.Forms.Control! ;-)
Konrad Rudolph
+1  A: 

In all cases, the IRenderable objects would also have to implement ILocateable, so I'm doing what @Sklivvz suggested and make IRenderable inherit (is that what its called when talking about interfaces?) from ILocateable:

public interface IRenderable : ILocateable
{
  // IRenderable interface
}

This pattern is used heavily in .NET. For example, the ICollection interface implements IEnumerable, while adding additional methods. This is a direct analogy to what the above code would do.

Thanks @Sklivvz.

Mark A. Nicolosi