tags:

views:

245

answers:

3

I have the following example code:

class A(object):
    def __init__(self, id):
        self.myid = id
    def foo(self, x):
        print 'foo', self.myid*x

class B(A):
    def __init__(self, id):
        self.myid = id
        self.mybid = id*2
    def bar(self, x):
        print 'bar', self.myid, self.mybid, x

When used, the following could be generated:

>>> a = A(2)
>>> a.foo(10)
foo 20
>>> 
>>> b = B(3)
>>> b.foo(10)
foo 30
>>> b.bar(12)
bar 3 6 12

Now lets say I have some more subclasses class C(A): and class D(A):. I also know that the id will always fit in either B, C or D, but never in 2 of them at the same time.

Now I would like to call A(23) and get an object of the correct subclass. Something like this:

>>> type(A(2))
<class '__main__.B'>
>>> type(A(22))
<class '__main__.D'>
>>> type(A(31))
<class '__main__.C'>
>>> type(A(12))
<class '__main__.B'>

Is this impossible or is it possible but just bad design? How should problems like this be solved?

+5  A: 

You should rather implement Abstract Factory pattern, and your factory would then build any object you like, depending on provided parameters. That way your code will remain clean and extensible.

Any hack you could use to make it directly can be removed when you upgrade your interpreter version, since no one expects backwards compatibility to preserve such things.

EDIT: After a while I'm not sure if you should use Abstract Factory, or Factory Method pattern. It depends on the details of your code, so suit your needs.

Abgan
+1  A: 

Generally it's not such a good idea when a superclass has any knowledge of the subclasses.

Think about what you want to do from an OO point of view.

The superclass is providing common behaviour for all objects of that type, e.g. Animal. Then the subclass provides the specialisation of the behaviour, e.g. Dog.

Think of it in terms of an "isa" relationship, i.e. a Dog is an Animal.

An Animal is a Dog doesn't really make sense.

HTH

cheers,

Rob

Rob Wells
+1  A: 

I don't think you can change the type of the object, but you can create another class that will work like a factory for the subclasses. Something like this:

class LetterFactory(object):
    @staticmethod
    def getLetterObject(n):
     if n == 1:
      return A(n)
     elif n == 2:
      return B(n)
     else:
      return C(n)

a = LetterFactory.getLetterObject(1)
b = LetterFactory.getLetterObject(2)
...
che
I am not sure why LetterFactory has to be a class. Having it defined as a `letter_factory` function would make things easier (e.g. no need for `LetterFactory.getLetterObject` calls, just `letter_factory` calls)
ΤΖΩΤΖΙΟΥ