Removing inheritance (decorator pattern ?)
Diez B. Roggisch
deets at nospam.web.de
Mon Jun 16 05:04:52 EDT 2008
Diez B. Roggisch wrote:
> George Sakkis schrieb:
>> 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:
>>
>> class Joinable(object):
>> def __init__(self, words):
>> self.__words = list(words)
>> def join(self, delim=','):
>> return delim.join(self.__words)
>>
>> class Sorted(Joinable):
>> def __init__(self, words):
>> super(Sorted,self).__init__(sorted(words))
>> def join(self, delim=','):
>> return '[Sorted] %s' % super(Sorted,self).join(delim)
>>
>> class Reversed(Joinable):
>> def __init__(self, words):
>> super(Reversed,self).__init__(reversed(words))
>> def join(self, delim=','):
>> return '[Reversed] %s' % super(Reversed,self).join(delim)
>>
>> 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()
>>
>>
>> So I'm wondering, is the decorator pattern applicable here ? If yes,
>> how ? If not, is there another way to convert inheritance to
>> delegation ?
>
> Factory - and dynamic subclassing, as shown here:
>
> import random
>
> class A(object):
> pass
>
> class B(object):
> pass
>
>
> def create_instance():
> superclasses = tuple(random.sample([A, B], random.randint(1, 2)))
> class BaseCombiner(type):
>
> def __new__(mcs, name, bases, d):
> bases = superclasses + bases
> return type(name, bases, d)
>
> class Foo(object):
> __metaclass__ = BaseCombiner
> return Foo()
>
> for _ in xrange(10):
> f = create_instance()
> print f.__class__.__bases__
Right now I see of course that I could have spared myself the whole
__metaclass__-business and directly used type()... Oh well, but at least it
worked :)
Diez
More information about the Python-list
mailing list