Sign in to follow this  
Cypher777

[.net] Design Question

Recommended Posts

I'm working on a simple real time strategy engine in C#. This engine is meant to be generic enough where the actual units/models/events are defined in external files and loaded in at run-time. I'm trying to follow a well-defined, logical structure for defining objects using the interface features. (Interfaces define a way of implementing a particular functionality, as opposed to inheritence which is more geered towards extending functionality.) So far, I have a base object, GObject, which every concrete unit will inherit from:
public class GObject
{
     private bool isInvincible;
     private bool isActive;
     private int maxHp;
     private int currentHp;
     // etc
     /* other stuff goes here */
}

Ideally, I would like to implement such functionality as a resource collector, producer, or docker as interfaces, so to define a "stronghold" type building unit that can store things inside of it:
public class GBuildDock : GObject, IDocker, IProducer
{
}

The problem I'm running into is that I would have liked to define an interface like IDocker as:
public interface IDocker
{
     int maxCapacity;
     int currentCapacity;
     // etc
     public Capacity
     {
         get   {   return currentCapacity;    }
         set   {   currentCapacity = ( value >= 0 ? value : 0 );  }
     }
     // ...and so forth

Of course, C# does not allow interfaces to have data members, only functions, indexers, and properties. One of two possible solutions to this is to put ALL the data members originally defined in ALL the interfaces in the base class, and just restrict access to them:
public class GObject
{
     private bool isInvincible;
     private bool isActive;
     private int maxHp;
     private int currentHp;
     // IDocker specific members
     protected int currentCapacity;
     protected int maxCapacity;
     // IProducer specific members
     // etc
     // ICollector specific members
     // etc
     /* other stuff goes here */
}

public interface IDocker
{
     public int Capacity
     {
         get   {   ;  }
         set   {   ;  }
     }
     // ...and so forth
}

public class GBuildDock : GObject, IDocker, IProducer
{
     public int Capacity
     {
         get   { return base.currentCapacity;  }
         set   { base.currentCapacity = ( value >= 0 ? value : 0 );
     }
     public int MaxCapacity
     {
        // more stuf goes here
     }
     // IDocker properties
     // IProducer properties
}

The other possible solution involves inheritence on many levels since C# does not allow multiple inheritence. To implement the functionality described above in GBuildDock, I'd have to follow a simulated multiple inheritence pattern (see http://www.codeproject.com/csharp/smip.asp). For an "easy to modify engine," I can throw this solution out, leaving the interface solution. The problem with this solution is that all of the data members are defined in the base class, which is wasteful, and the base object has to be modified everytime a new interface is defined. Anybody have any better ideas on how to go about solving this problem, or am I stuck with the interface solution? Thanks in advance.

Share this post


Link to post
Share on other sites
Adding the members to the universal base class is a bad idea: it removes the whole point of separating out the interfaces in the first place!

The 'correct' way to do this is undoubtedly via interfaces. Admittedly that involves putting the actual code in a number of places, and to get around that you may want to define basic classes of unit that implement the common interface, i.e.

public interface ITransporter {
// for freighters and suchlike
ResourceType ResourceType {get; set;}
int Capacity { get; }
int Amount { get; set; }
// ... etc
}


public abstract class BasicTransporter : ITransporter {
private int capacity, amount;
private ResourceType rtype;
public int Capacity {
get { return capacity; }
set { capacity = value; }
}
// etc
}


Then most of your units and buildings can inherit from those base classes. Only oddball cases (like something which is both a resource transporter and an APC) will have to implement the interfaces themselves.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this