Reputation: 3832
This question concerns design patterns in Python and is addressed to the software designers.
I have several classes inherited from the same abstract class (all they have a similar interface, but the member functions have very different implementations). I want to make a class (or something else) that combines (wraps) all of them. By combining I mean a pattern that creates and returns an object a certain class depending on the input parameters. The most trivial solution is a Python function:
def fabric_function(arg):
if isinstance(arg, float):
return Class1(arg)
if isinstance(arg, str):
return Class2(arg)
Is there a better pattern available to do it? I would really prefer it to be a class that returns either object of Class1
or Class2
depending on parameters. I want the user to make an instance of a class Class
that operates as an instance of the Class1
or Class2
depending on input parameters so the user does not have to make a decision on which of them to use and the output from type(obj)
should be Class
in all cases. In this case, I could modify the member function __new__
responsible for the object making process, but I am not sure it is a clean way to do it. Maybe I should use multiple inheritance and decide in the constructor which parent class to inherit for real?
Upvotes: 2
Views: 1204
Reputation: 626
This is easy in Python. Use __new__
!
In python, when an instance is made, aka the class is called, the special method __new__
is called. You can override it, like any method/operator in python.
Typically, one does so in the base class (aka interface). So, your suggestion is right.
The implementation is simple: mostly the code you provided in this “factory”. Although you might add a few details like checks to prevent strange behavior when using unexpected/unwanted arguments or subclasses.
Remember, returning None
is fine. Actually anything is allowed (but unwise, when you’re not what to disturb your users)
Upvotes: 0
Reputation: 442
I did something similar once using a dictionary. I requires the init functions of your derived classes to have the same signatures in order to work.
Use a dictionary with some immutable type of your choice as key and put the classnames as values:
TYPE_MAP = {typeA: Class1,
typeB: Class2,
typeC: Class3}
def fabric_function(arg):
return TYPE_MAP[type(arg)](arg)
I'm not exactly sure how pythonic/clean you consider this but it helped me greatly in avoiding this if isinstance...
chain you posted above. Also it is very easy to extend as you only have to adjust the dictionary and not the factory function.
Upvotes: 1
Reputation: 1165
I suppose that Class1
and Class2
are related somehow (eg, "Square" and "Circle" are both "Figures" ). What you are describing is an Abstract Factory.
You need a class exposing a Create()
method, accepting the bare minimum context that would help you find out what's the concrete implementation to instantiate.
Upvotes: 1