Removing inheritance (decorator pattern ?)

George Sakkis george.sakkis at gmail.com
Mon Jun 16 14:35:22 EDT 2008


On Jun 16, 1:49 pm, Gerard flanagan <grflana... at gmail.com> wrote:

> George Sakkis wrote:
> > I have a situation where one class can be customized with several
> > orthogonal options. Currently this is implemented with (multiple)
> > inheritance but this leads to combinatorial explosion of subclasses as
> > more orthogonal features are added. Naturally, the decorator pattern
> > [1] comes to mind (not to be confused with the the Python meaning of
> > the term "decorator").
>
> > However, there is a twist. In the standard decorator pattern, the
> > decorator accepts the object to be decorated and adds extra
> > functionality or modifies the object's behavior by overriding one or
> > more methods. It does not affect how the object is created, it takes
> > it as is. My multiple inheritance classes though play a double role:
> > not only they override one or more regular methods, but they may
> > override __init__ as well. Here's a toy example:
>
> I don't know if it will map to your actual problem, but here's a
> variation of your toy code. I was thinking the Strategy pattern,
> different classes have different initialisation strategies? But then you
> could end up with as many Strategy classes as subclasses, I don't know.
> (Also in vaguely similar territory -http://bazaar.launchpad.net/~grflanagan/python-rattlebag/trunk/annota...
> )
>
> class MetaBase(type):
>
>      def __init__(cls, name, bases, data):
>          cls.strategies = []
>          cls.prefixes = []
>          for base in bases:
>              print base
>              if hasattr(base, 'strategy'):
>                  cls.strategies.append(base.strategy)
>              if hasattr(base, 'prefix'):
>                  cls.prefixes.append(base.prefix)
>          super(MetaBase, cls).__init__(name, bases, data)
>
> class Joinable(object):
>      __metaclass__ = MetaBase
>      strategy = list
>      prefix = ''
>
>      def __init__(self, words):
>          self._words = words
>          for strategy in self.strategies:
>              self._words = strategy(self._words)
>
>      def join(self, delim=','):
>          return '%s %s' % (' '.join(self.prefixes), delim.join(self._words))
>
> class Sorted(Joinable):
>      strategy = sorted
>      prefix = '[sorted]'
>
> class Reversed(Joinable):
>      strategy = reversed
>      prefix = '[reversed]'
>
> class SortedReversed(Sorted, Reversed):
>      pass
>
> class ReversedSorted(Reversed, Sorted):
>      pass
>
> if __name__ == '__main__':
>      words = 'this is a test'.split()
>      print SortedReversed(words).join()
>      print ReversedSorted(words).join()

This doesn't solve the original problem, the combinatorial explosion
of empty subclasses. At the end of the day, I'd like a solution that
uses a (mostly) flat, single-inheritance, hierarchy, allowing the
client say:

j = Joinable(words)
if sort:
  j = Sorted(j)
if reverse:
  j = Reversed(j)
...
print j.join()


George



More information about the Python-list mailing list