OO refactoring trial ??

Paul McGuire ptmcg at austin.rr.com
Wed Jun 29 00:18:24 EDT 2005


Lee -

Bruce Eckel's observation:

"the above scaffolding of Obstacle, Player and GameElementFactory
(which was translated from the Java version of this example) is
unnecessary - it's only required for languages that have static
type checking. As long as the concrete Python classes follow the form
of the required classes, we don't need any base classes..."

is consistent with my "duck-typing" comment that all that is needed of
A,B,etc. is that they provide the necessary testit and doit methods in
the proper form.  He also goes on to say that, even if the base classes
were empty, they still provide a useful handle for all of the derived
classes, to indicate they are all common subtypes of "Shape" or
whatever.

I think you were referring to the "Poking Python with a Stick" entry in
the second link.  The inheritance of all taunts from Taunt allowed the
author to put some overriding common-to-all-taunts behavior into the
superclass, even if it was just a "sorry, not implemented" exception
into the base Taunt class's tauntTheKnights() method.  The idea was to
provide a runtime exception if the needed method had not been
overridden in the subclass.  But it also provides a place to put any
other common-to-all-taunts behavior, perhaps a common constructor, or
other common helper methods.  I think this is a good use of
inheritance, when the base class actually adds some value to the
architecture, even if it is just Bruce Eckel's empty placeholder base
class.  Note also that this author was doing patterns experimentation
in both Python and Java.  I envision him writing the factory's
getInstance() method in Java, and having to declare its return value
type.  In this case Java really drives you to having all possible
return values derive from a common base class, so that you can define
the method as:

	Taunt getInstance(string tauntTypeTag) { ...

which is a bit easier to deal with than just declaring that getInstance
returns an object, and then having to cast it - in fact, if there were
no common base type, it would be problematic to know just what to cast
it to.

But Python does not require this sort of type rigidity.  In your code,
the only requirement is that each class A,B,etc. have testit and doit
methods - they have to walk and talk like ducks, they don't need to
*be* ducks.  My point in an earlier post was, I think many current
design patterns were born out of the C++ and Java worlds, and may be
overly restrictive for a comparable implementation in Python.

One step you might take in the MultiEvaluator constructor is to
validate the provided classes on input, so that you don't have to
exhaustively test all A thru Z classes before finding out that you
misspelled Z's doit method as "dooit".  This goes one better than the
abstract subclass's "you forgot to override me" method implementation.

In sum, both of the links you sent used examples that had inheritance
hierarchies where the base class provided some contribution and
commonality among the derived classes.  TauntArthur "is-a" Taunt,
TauntGalahad "is-a" Taunt.  It really does look like the Factory
pattern should return objects that share a common base class.  But in
Python, that common base class can also be just "something that walks
like a duck."

-- Paul




More information about the Python-list mailing list