Yanka Smetanka
Yanka Smetanka

Reputation: 11

Fixing Abstract Factory in Python

I'm trying to implement Abstract Factory pattern in Python, but after creating new "product" it simply does not work and I can't firuge out what's the problem. Here's a code:

`from __future__ import annotations
from abc import ABC, abstractmethod
# AbstractFactory
class AbstractCarFactory(ABC):
@abstractmethod
def create_product_car(self) -> AbstractProductCar:
    pass

@abstractmethod
def create_product_engine(self) -> AbstractProductEngine:
    pass

@abstractmethod
def create_product_wheel(self) -> AbstractProductWheel:
    pass


class FordFactory(AbstractCarFactory):
def create_product_car(self) -> AbstractProductCar:
    return Ford()

def create_product_engine(self) -> AbstractProductEngine:
    return FordEngine()

def create_product_wheel(self) -> AbstractProductWheel:
    return FordWheel()


class ToyotaFactory(AbstractCarFactory):
def create_product_car(self) -> AbstractProductCar:
    return Toyota()

def create_product_engine(self) -> AbstractProductEngine:
    return ToyotaEngine()

def create_product_wheel(self) -> AbstractProductWheel:
    return ToyotaWheel()


class MercedesFactory(AbstractCarFactory):
def create_product_car(self) -> AbstractProductCar:
    return Mercedes()

def create_product_engine(self) -> AbstractProductEngine:
    return MercedesEngine()

def create_product_wheel(self) -> AbstractProductWheel:
    return MercedesWheel()


class AbstractProductCar(ABC):
@abstractmethod
def info_car(self) -> str:
    pass

def interact1_car(self, collaborator: AbstractProductEngine) -> str:
    pass

def interact2_car(self, collaborator: AbstractProductWheel) -> str:
    pass


class AbstractProductEngine(ABC):
@abstractmethod
def get_power(self) -> str:
    pass


class FordEngine(AbstractProductEngine):
def get_power(self) -> str:
    return "Ford Engine"


class ToyotaEngine(AbstractProductEngine):
def get_power(self) -> str:
    return "Toyota Engine"


class MercedesEngine(AbstractProductEngine):
def get_power(self) -> str:
    return "Mercedes Engine"


class AbstractProductWheel(ABC):
@abstractmethod
def get_wheel(self) -> str:
    pass


class FordWheel(AbstractProductWheel):
def get_wheel(self) -> str:
    return "Ford Wheel"


class ToyotaWheel(AbstractProductWheel):
def get_wheel(self) -> str:
    return "Toyota Wheel"


class MercedesWheel(AbstractProductWheel):
def get_wheel(self) -> str:
    return "Mercedes Wheel"


class Ford(AbstractProductCar):
def info_car(self) -> str:
    return "Ford"

def interact1_car(self, collaborator: AbstractProductEngine) -> str:
    result1 = self.info_car() + " set Engine " + collaborator.get_power()
    return f"Result of setting engine to the body: ({result1})"

def interact2_car(self, collaborator: AbstractProductWheel) -> str:
    result2 = self.info_car() + " set Wheels " + collaborator.get_wheel()
    return f"Result of final assembly: {result2}"


class Toyota(AbstractProductCar):
def info_car(self) -> str:
    return "Toyota"

def interact1_car(self, collaborator: AbstractProductEngine) -> str:
    result1 = self.info_car() + " set Engine " + collaborator.get_power()
    return f"Result of setting engine to the body: ({result1})"

def interact2_car(self, collaborator: AbstractProductWheel) -> str:
    result2 = self.info_car() + "set Wheels " + collaborator.get_wheel()
    return f"Result of final assembly: {result2}"


class Mercedes(AbstractProductCar):
def info_car(self) -> str:
    return "Mercedes"

def interact1_car(self, collaborator: AbstractProductEngine) -> str:
    result1 = self.info_car() + " set Engine " + collaborator.get_power()
    return f"Result of setting engine to the body: ({result1})"

def interact2_car(self, collaborator: AbstractProductWheel) -> str:
    result2 = self.info_car() + "set Wheels " + collaborator.get_wheel()
    return f"Result of final assembly: {result2}"

def client_code(factory: AbstractCarFactory) -> None:
product_a = factory.create_product_car()
product_b = factory.create_product_engine()


print(f"{product_a.interact1_car(product_b)}"
     f"{product_a.interact2_car(product_b)}")


if __name__ == "__main__":
print("Client: Testing first factory:")
client_code(FordFactory())

print("Client: Testing second factory:")
client_code(ToyotaFactory())

print("Client: Testing third factory:")
client_code(MercedesFactory())

I've already tried to create abstract client code instead of copying it every time but it doesn't help. Even ChatGPT can't tell what's te matter lol

Upvotes: 1

Views: 44

Answers (1)

jamied157
jamied157

Reputation: 61

I'm assuming the code you've sent was indented incorrectly when copying and pasting as a lot of the methods for classes are inline with the class definition. After fixing that I ran your code and got:

python3 test.py     
Client: Testing first factory:
NoneNone
Client: Testing second factory:
Traceback (most recent call last):
  File "/Users/jamied/git/pseudocode/test.py", line 157, in <module>
    client_code(ToyotaFactory())
  File "/Users/jamied/git/pseudocode/test.py", line 149, in client_code
    f"{product_a.interact2_car(product_b)}")
  File "/Users/jamied/git/pseudocode/test.py", line 127, in interact2_car
    result2 = self.info_car() + "set Wheels " + collaborator.get_wheel()
AttributeError: 'ToyotaEngine' object has no attribute 'get_wheel'

It looks like the second method you created interact2_car was meant to interact with a AbstractProductWheel class but instead you gave it a AbstractProductEngine class. Maybe this is what you meant to do?

def client_code(factory: AbstractCarFactory) -> None:
    product_a = factory.create_product_car()
    product_b = factory.create_product_engine()
    product_c = factory.create_product_wheel() # I added this


    print(f"{product_a.interact1_car(product_b)}"
        f"{product_a.interact2_car(product_c)}") # now using product c

Then running this gives

python3 test.py
Client: Testing first factory:
Result of setting engine to the body: (Ford set Engine Ford Engine)Result of final assembly: Ford set Wheels Ford Wheel
Client: Testing second factory:
Result of setting engine to the body: (Toyota set Engine Toyota Engine)Result of final assembly: Toyotaset Wheels Toyota Wheel
Client: Testing third factory:
Result of setting engine to the body: (Mercedes set Engine Mercedes Engine)Result of final assembly: Mercedesset Wheels Mercedes Wheel

Which is hopefully what you wanted?

ps. it's usually helpful to post the error message when asking a question like this, it makes it easier to see what the problem is.

Upvotes: 1

Related Questions