The assignment contains these instructions:
Part II – Factory Class
This class acts as the base class for other concrete Fruit classes, like Orange and Apple. As the title hints at, this class will also serve as the factory for those derivative classes. This class should have the following methods:
__init__(self)
- This method is mostly a placeholder. Print a message when it is called while debugging.
price(self)
- Returns the price of the item.
- This is also a placeholder for use by derived classes. It only needs to return 0.
prepare(self)
- This method is a placeholder for use by derived classes.
- In derived classes, this method acts as a façade that encapsulates the complex process for preparing fruits.
order_fruit(fruit_type) # Notice no 'self'
- This method acts as the factory method for making fruit objects.
- This method should be static so mark it with the
@staticmethod
decorator.- Here’s the process for kicking off the factory:
- Make sure
fruit_type
is a string and trim and convert it to lower case- Create the object of the type called for by the string
- So if it is “orange”:
fruit = Orange()
- Once your fruit object is created, you will call its
prepare()
method
I need help with the part in bold. I have this:
class Fruit():
def __init__(self):
print(f"Fruit.__init__")
def price(self):
return 0
def prepare(self):
print(f"Preparing {fruit}")
@staticmethod
def order_fruit(fruit_type):
fruit = str(fruit_type.lower().strip())
prepare(fruit)
I can't figure out how to get it to call, for example, Orange.prepare()
in order_fruit
.
I might be misunderstanding the instructions.
Here's one way to do it that uses a dictionary that maps the names of all the derived classes to the corresponding subclass itself.
class Fruit():
def __init__(self):
print(f"Fruit.__init__()")
def price(self):
return 0
def prepare(self):
print(f"Preparing {type(self).__name__}")
@staticmethod
def order_fruit(fruit_type):
# Dictionary of all derived classes.
derived_classes = {'Apple': Apple, 'Orange': Orange}
fruit = str(fruit_type.lower().strip())
for classname, FruitSubclass in derived_classes.items():
if classname.lower() == fruit:
fruit = FruitSubclass()
fruit.prepare()
break
else:
raise RuntimeError(f'Unknown fruit type {fruit_type!r}')
class Orange(Fruit):
def __init__(self):
print(f"Orange.__init__()")
class Apple(Fruit):
def __init__(self):
print(f"Apple.__init__()")
if __name__ == '__main__':
fruit = Fruit.order_fruit('orange')
One potential issue with this approach is that it requires manually updating the base class everytime a new subclass gets added.
There are also other more advanced ways of doing the same thing. See my answer to Improper use of __new__
to generate classes?.