Puzzling OO design problem

Jack Diederich jack at performancedrivers.com
Fri Apr 8 22:54:20 EDT 2005


On Fri, Apr 08, 2005 at 06:40:54PM -0700, George Sakkis wrote:
> > Err, you might want to explain what these things do instead of an
> > abstract description of how you are doing it.  It looks like you are
> > using inheritance in the normal way _and_ you are using it to handle
> > versioning of some kind (maybe stable interface releases? I don't
> know).
> >
> > Let us know what parts need inheritance for, and what you have
> > just been using a side effect of inheritance for as a convenience
> > (versioning, I think).
> >
> > A more concrete example would be easier to comment on, if possible
> > do a simple one (maybe just two classes with two versions each).
> >
> > -jackdied
> 
> I intentionally abstracted the problem to remove the irrelevant
> details, but here's a more concrete (though still simplified) example.
> I hope it is more clear now.

<boiled down version of George's exmaple>

> def worldModelFactory(version):
>     if version < 2: return WorldModel()
>     else: return WorldModel_v2()
> 
> class WorldModel_v1(object):
>     class Player(object):
>       def foo(self): pass # v1 implementation of foo()
>
> class WorldModel_v2(object):
>     class Player(WorldModel_v2.Player):
>       def foo(self): pass # v2 implementation of foo()

So you are using the WorldModel_* classes as a namespace to hold a
set of classes that might inherit and extend or redefine the previous
classes in a WorldModel_* namespace.  This seems to do what you wanted
in your original post, namely if a class is defined in v1 but not in v2
that v2 would just use v1's implementation.  WorldModel_v2 will inherit
Player from _v1 by default, so that should work OK out of the box.

So you should be fine there, but I think your question is more practical
than "what is the proper OO way to do it?" which is a bit of a shibboleth
in python.  We like "what is easiest and readable?" So here are some
practical recommendations (well, at least that's my intention).

Are you using the *_v1 naming convention for backwards compatibility?
Backwards compatibility is a giant pain in the ass, I notice you are
posting from a .edu address so if this is just something you are working
on by yourself or in a small group drop the versioning aspects from the
code.  Talking to the other people in the group is easier.

>From your example (which I over-pruned) it looks like you are using
the WorldModel namespace to define parameters for running an iteration
of a game.  The classes under "WorldModel" are something like
the rules/physics definition (MovableObject), coordinates of the team-A
goalpost, coordinates of the team-B goalpost, team-A strategy (Player), 
and team-B strategy (also Player).  WorldModel would be the gameboard.

If so, make WorldModel just a board - drop putting Player etc under it
as a namespace,  and give it a run() function that takes parameters.
Name the Player derivatives as PlayerDumb,  PlayerSmart, PlayerAggressive 
etc, you'll probably have a lot more of those than goals or physics rules.
The actual main routine would look something like

ob = WorldModel() # standard 100x100 board
winner = ob.run(physics=MovableObject,  # defines friction and gravity
                team_a_goal=(50,25),
                team_b_goal=(5,5),
                team_a_strategy=PlayerDumb,
                team_b_strategy=PlayerAggressive,
               )
print "Winner is ", winner

I wrote more than I meant to, but the basic idea is don't use classes
when you don't need to - it just makes things more complex.  That 
should give you more time to tackle the interesting parts (player 
strategies, I'd imagine).

-jackdied



More information about the Python-list mailing list