Inheritence confusion

Robert Brewer fumanchu at amor.org
Fri Jun 11 19:44:38 EDT 2004


Kirk Strauser wrote:
> OK, then, I shall again ask advice.  I foresee having 10-15 completely
> distinct classes for clients to choose from.  I don't want to 
> end up in the
> position where a client program has to know that if it's importing
> FtpEdiFiles, then it has to use the FtpEdiFileRetriever 
> class, but if it's
> importing ScpPngFiles, then it has to use the 
> ScpPngFileRetriever class.  I
> really want to use the same class name across all of the 
> modules unless
> doing otherwise is unavoidable.  What's a good way to handle this?

Some block of code somewhere has to "know" and decide which strategy to
use, which is why the Strategy Pattern (cf
http://home.earthlink.net/~huston2/dp/strategy.html) is named as it is.
If you don't want your clients to decide, then you must put that
decision somewhere else. As I see it (not having a clear picture of your
whole app), you have two choices:

1) The client knows its importing FtpEdiFiles because it somehow
obtained an FtpEdiFile object:

class File(object):
    retriever = None
    
    def retrieve(self):
        return self.retriever.pull(self.resource)

class FtpEdiFile(File):
    retriever = FtpEdiFileRetriever()


2) The client doesn't really know what it's doing. In this case, the
client has to have a reference to some kind of Context or Application
object which *does* know, and can dispatch based on which File and
Retriever objects it possesses (again, using composition):

class File(object):
    pass

class FtpEdiFile(File):
    pass

class Retriever(object):
    def retrieve(self, fileobj):
        raise NotImplementedError

class FtpEdiFileRetriever(Retriever):
    def retrieve(self, fileobj):
        ftplib.open(fileobj)
        ...etc
        return data

class App(object):
    def retrieve(self):
        self.retriever.retrieve(self.FileProxy)

...and somewhere in client code:

MyApp = App()
MyApp.FileProxy = FtpEdiFile()
MyApp.Retriever = FtpEdiFileRetriever()
# Time passes
MyApp.FileProxy.resource = "ftpserver.company.com/readme"
stuff = MyApp.retrieve()

Notice that the last line doesn't "know" anything about the file type or
retriever. By defining an interface which all Retriever subclasses
share, you abstract that code. Client code has to select the appropriate
subclass *sometime*, but by using composition and delegation, that
should only happen once (usually at app startup, or per request).

I hope I'm addressing your question. Hard to do in text. ;)


Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org




More information about the Python-list mailing list