Lets suppose we have an entity (Car) with different CarTypes:
class CarTypes(Enum):
SUV = 'suv'
SPORT = 'sport'
@dataclass
class Car:
id: UUID
type: CarTypes
owner: str
def run(self):
...
def idk_some_car_stuf(self, speed):
...
The class Car implements the domain rules referring to Car, and the application rules (ie, acces DB to load Car, access external APIs, put messages on queues, logs, etc) are implemented in a service class CarService:
class ServiceCar:
def __init__(self, car_id: UUID):
self._car = CarRepository.get(car_id)
def run(self):
log.info('Car is about to run')
self._car.run()
if self._car.type == CarTypes.SUV:
suvAPI.suv_is_running(self._car)
elif self._car.type == CarTypes.SPORT:
...
rabbitmq.publish({'car': self._car.__dict__, 'message': ...})
The problem is that different car types can have different application rule types (eg calling different external APIs, etc.) and since I want to follow the Open-Closed principle, I dont want to implements this ifs, so I choose to segregate CarService by CarTypes like this:
class CarService(ABC):
@abstractmethod
def run(self) -> None:
...
class SUVCarService(CarService):
''' Specific implementation here, following CarService interface'''
...
class SportCarService(CarService):
''' Specific implementation here, following CarService interface'''
...
class CarServiceFactory:
@classmethod
def build(cls, car_id: UUID) -> CarService:
car = CarRepository.get(car_id)
klass: CarService = SUVCarService if car.type == 'SUV' else SportCarService
return klass(car)
That is my current implementation (oc I used an generic and simples example here ) but im not satisfied, what I really want is to use Metaclasses to build the specific (ie SUVCarService and SportCarService). So, instead my controllers call something like this:
def controller_run(body):
service = CarServiceFactory.build(body['car_id'])
service.run()
...
It would be call something like:
def controller_run(body):
service = CarService(car_id=body['car_id'])
# This CarService calls return the specific class, so
# if car.type == 'suv' then type(service) == SUVCarService
service.run()
...
But the python documentation about metaclasses are confuse to me, (idk if I need to use __new__ method from the metaclass itself, or __prepare__ ).