[MUD-Dev] Re: A Small Conceptual Object System For MUDs
Mark Gritter
mark at erdos.Stanford.EDU
Mon Nov 9 15:38:43 CET 1998
Emil Eifrem writes:
[snip]
>
> As for Java, I suppose the obvious solution is to use interfaces. I don't
> particularly like that. I believe the way most low-hierarchy mud world
> objects differ isn't in the messages they accept, but rather in the
> implementation. Both the sword and the banana objects accept the eatMe()
> message -- where they differ is the implementation. I think the busswords
> are 'implementation inheritance' vs 'interface inheritance.' Thus, Java
> interfaces wouldn't really help.
>
> As far as I can see there are two extreme solutions to this problem.
>
> i) Have only one base abstract class (Entity) and the rest specified as
> interfaces (Item, Weapon, Sword, Flower, Banana). Consequences: A builder
> that wished to make a banana-key (I assume runtime extension of the world)
> would have to provide *all* implementation for the specifics declared by
> the Fruit and Key interfaces. Not good for the poor builder. And even if
> the object hierarchy was static and compiled into the driver, this would
> still mean a *lot* of duplicate code in the world implementation.
>
The underlying assumption that I would like to challenge here is that
an interface must be implemented by the _same_ language-level object that
provides it. Given this restriction, you're entirely right: anybody using
single inheritance must implement _all_ of Fruit and _all_ of Key, but
can only inherit from one Fruit implementation of Key implementation.
(They may be able to make their implementation job _easier_ by using
delegation, but there are still some ugly issues you can get yourself
into--- say somebody goofed and two interfaces contain the same
function signature, but have different semantics for it.)
Suppose, though, (sticking with Java) that the Entity class contains a
method like "Object getInterface(Class c);"
When other code wishes to interact with an entity, it uses this function
to ask for an interface. The returned Object might be the Entity itself
(if it directly supports that interface), or a "trampoline" object that
just delegates function calls... or a full-fledged implementation of
that interface.
>From the "client" side of things, it doesn't matter. Once I've
requested "getInterface(Fruit.class)", all I care about is that it
acts like a Fruit--- which it does.
The implementation side is almost as nice. Default implementations of
Fruit, Key, etc. need to be written in such a way that they can handle
the "real" Entity object being different from their subclass. But
this can be handled by subclassing them from an Entity which just delegates
all Entity calls to a stored reference. (Assuming you're not directly
manipulating Entity data...)
A "standard" Banana would be subclass of Entity which provided only the
Fruit interface. The BananaKey could be a subclass of Banana (or
directly of Entity) which provides both Fruit and Key interfaces.
The default Fruit and Key implementations can be subclassed to
BananaKeyFruit and BananaKeyKey (OK, maybe that's a bad name) if the
behavior of a BananaKey is different than the standard Key or Banana---
but without re-writing the whole thing. On the other hand, I'm certainly
free to do so.
This scheme also allows multiple interface objects per "top-level"
object, which neither C++ nor Java directly supports. (I.e., can
only inherit a class or interface once.)
This is somewhat similar to the "Proxy" or "Adapter" design patterns.
Or to the approach used by OLE. (COM, DCOM, whatever they're calling
it these days.) My research group refers to it as "warthogology", for
reasons I won't go into at the moment. (And if my advisor ever got
his book published, I could actually give you a reference to look up,
too.)
Mark Gritter
mar at erdos.stanford.edu
More information about the mud-dev-archive
mailing list