Removing inheritance (decorator pattern ?)

George Sakkis george.sakkis at gmail.com
Tue Jun 17 20:50:34 CEST 2008


On Jun 16, 11:10 pm, Maric Michaud <ma... at aristote.info> wrote:

> Le Monday 16 June 2008 20:35:22 George Sakkis, vous avez écrit :
>
>
>
> > 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:
>
> Yes, and it fails to implement the strategy pattern as well... which would
> have solved the problem as it is intended exactly for this purpose.

As someone in another newsgroup demonstrated, it can be solved with a
combination of strategy and decorator: http://tinyurl.com/5ulqh9

George



More information about the Python-list mailing list