Design pattern question

Eric Brunel eric.brunel at pragmadev.com
Wed Aug 21 10:19:23 CEST 2002


Karl Schmid wrote:

> Hi,
> 
> I would like to separate an abstraction from its implementation. I think
> this is called the Bridge pattern by Gamma et al. (or at least it is a
> part of a bridge pattern).
> 
> In particular, I would like to assemble a set of DNA sequences and have
> the option to chose among different assembly algorithms. I am not sure
> what the best way to do this would be:
> 
> 
> class SequenceAssembler:
>         
>     def __init__(self,assembler_type):
> 
>         if assembler_type == 'cap3':
>             # What should I do here?
>         elif assembler_type == 'phrap':
>             # What should I do here?
> 
>     def save_sequences():
>         pass
> 
> class Cap3Assembler(SequenceAssembler):
> 
>     def run_assembler():
>         # Cap3 specific instructions
>         pass
> 
> class PhrapAssembler(SequenceAssembler):
> 
>     def run_assembler():
>         # Phrap specific instructions
>         pass
> 
> Now I would like to instantiate the abstract class, but to obtain an
> instance of either the Cap3Assembler or PhrapAssembler class depending on
> the assembler_type variable.
> 
>>>> assembler = SequenceAssembler(assembler_type)
> 
> Is this possible?

AFAIK, there's not a single OO language that allows to do this this way. In 
Python, I saw once that it's possible to assign a new value to the 
__class__ attribute of an object, so *theoretically*, Python object can 
dynamically change their class. But this attribute is certainly not meant 
to be changed and doing so may certainly have unpredictable results. If 
anyone knows better, please let me know...

The solution I'd adopt is to use another design pattern: the abstract 
factory:

class SequenceAssembler:
  ...

class Cap3Assembler(SequenceAssembler):
  def run_assembler(self):
    ...

class PhrapAssembler(SequenceAssembler):
  def run_assembler(self):
    ...

class SequenceAssemblerFactory:
  type2Class = {
    'Cap3' : Cap3Assembler,
    'Phrap' : PhrapAssembler
  }
  def newSequencerAssembler(self, assemblerType):
    return SequenceAssemblerFactory.type2Class()

fact = SequenceAssemblerFactory()
assembler = fact.newSequencerAssembler(assembler_type)

If you need the factory in many places, use yet another design pattern: 
singleton class:

class SequenceAssemblerFactory:

  type2Class = {
    'Cap3' : Cap3Assembler,
    'Phrap' : PhrapAssembler
  }

  theInstance = None

  def __init__(self):
    SequenceAssemblerFactory.theInstance = self

  def newSequencerAssembler(self, assemblerType):
    return SequenceAssemblerFactory.type2Class()

SequenceAssemblerFactory()
assembler = \
 SequenceAssemblerFactory.theInstance.newSequencerAssembler(assembler_type)

HTH
-- 
- Eric Brunel <eric.brunel at pragmadev.com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com



More information about the Python-list mailing list