10 Aug, 2010, JohnnyStarr wrote in the 1st comment:
Votes: 0
After several attempts to make my own mud-base (typically focusing on the server and command
interpreter) I've decided that it would be much more logical to first create the mud's library.
After studying up on inheritance, polymorphism, and composition, I'm a bit confused. Here's why:

Inheritance:

I've read that inheritance can "break encapsulation" if used improperly. I can see that having too
strict of a class hierarchy may lead to things becoming rigid along the way. A MUD is a good example
of system that requires scalability (you never know what you might want to add later).

Questions: How many derived classes is too many? Should base classes be avoided?

polymorphism: - specifically using interfaces (as in Java or C# structures)

The more I learn about Interfaces, the more I like them. But while going down this road, there
are some concerns along the way. One that comes to mind, is that if you implement class methods
without an interface, you are almost doing yourself a disservice. This could apply to any class
that could have similar behavior to another later on. So where do you draw the line? If I had
a Character class, and I were to implement IMoveable for instance, any user-controlled object
could implement the IMoveable interface and the object would "move()" or what have you. But if
I were to create a move() method for Character on it's own, it wouldn't be able to do something like:

foreach(IMovable ch in characters) { ch.move(); }


Not because Character does not have move(), but because Character is not shared type IMoveable.

Questions: Where do you draw the line on interfaces? Would it make most sense to always use them, even if you don't see any reason to create
objects with similar behavior at the time?


Composition:
Although this is it's own subject, it sort of ties together my concerns.

An example would be a Character or similar Entity's inventory:
1) You could use composition by creating an InventoryHelper object that could be utilized by anything in the game.
2) You could create an interface like ICarriesItems and have each entity class implement it's own features.
3) You could have all entity's inherit the base class EntityBase which would take care of the inventory.

Questions: How do you avoid the complexity of embedding objects that could very well be derived classes themselves? What are the main
benefits of composition?


Summary:
I am open to all viewpoints as this is probably more opinion based than anything. But I would also like examples of why you think one way is better than the other. My goal is to take in all points of view, and get past this hurdle.
10 Aug, 2010, David Haley wrote in the 2nd comment:
Votes: 0
I think that most of your questions are very hard to answer in general; the main answer I have for you is that it depends.

Regarding interfaces, though, there's no need to get too crazy creating an interface for every possible aspect of your character. I would code simply ay first and refactor later. You will find commonalities that are relevant to your game, and those should be what you turn into interfaces, base classes, etc.
12 Aug, 2010, JohnnyStarr wrote in the 3rd comment:
Votes: 0
When using interfaces, I think it's really cool that you can have several different classes
with similar behavior implement the same interface. Say I wanted a list of players, but of different
types: - in pseudo code

interface IPlayer { void LevelUp(); }

class Character : IPlayer { public void LevelUp() { _level++; }
class Ship : IPlayer { public void LevelUp() { _level++; _armor++;}
class Mech : IPlayer { public void LevelUp() { _level++; _guns++;}

// instead of having a list of Characters, or Ships, or Mechs, we can have a list of IPlayer

List<IPlayer> playas = new List<IPlayer>();

foreach(IPlayer ch in playas) { ch.LevelUp(); }


But what concerns me here, is that "ch" only has access to the methods defined in the IPlayer interface.
What if within the same loop we wanted to check to see if there are any Characters and perform an additional
action? The only way I can see is to do this:

foreach (IPlayer ch in playas) {
if (ch is Character) {
Character c = (Character)ch;
c.MethodOnlyBelongingToCharacter();
c.LevelUp();
} else ch.LevelUp();
}


Something here just doesn't feel right. I have noticed that CoffeeMud is riddled with this type of code
( only using the java equivalent operator "instanceof" )
12 Aug, 2010, David Haley wrote in the 4th comment:
Votes: 0
Well, usually if you stick them all together in one collection, it's that for the purposes of that collection you don't really care about their more specialized methods. That said, if for some reason you do, you can either push methods up to the IPlayer interface, or if that's really not appropriate, just use the instanceof method. Usually you let OOP do that sort of stuff for you, but in some cases it just makes more sense to test if something is of a particular type.
12 Aug, 2010, JohnnyStarr wrote in the 5th comment:
Votes: 0
Well, I agree that if you have a collection of a certain interface, that should be enough in most cases.
I suppose I need to rely mostly on a sound schema from the very beginning. So far, I'm really trying to
build my library as scalable as possible, without over engineering every facet of it.

One such aspect would be the command handler. I feel that commands should be first class objects that
are owned by each IPlayer type. I could easily make things very complicated, or overly simple. It's a
delecate balance that I suppose will come in time.
12 Aug, 2010, David Haley wrote in the 6th comment:
Votes: 0
Start with the straightforward solution, after having thought about it a little bit to make sure there is no obvious problem with it, and refactor over time as you discover that you actually need to.
0.0/6