Breve formato della domanda
Nelle migliori pratiche di DDD e OOP è possibile iniettare servizi sulle chiamate al metodo di entità?
Esempio di formato lungo
Diciamo che abbiamo il classico caso Order-LineItems in DDD, dove abbiamo un'entità di dominio chiamata Ordine, che agisce anche come radice di aggregazione, e che Entità è composta non solo da oggetti valore, ma anche da una collezione delle entità degli elementi pubblicitari.
Supponiamo di volere una sintassi fluente nella nostra applicazione, in modo che possiamo fare qualcosa di simile (osservando la sintassi nella riga 2, dove chiamiamo il metodo getLineItems
):
$order = $orderService->getOrderByID($orderID);
foreach($order->getLineItems($orderService) as $lineItem) {
...
}
Non vogliamo iniettare alcun tipo di LineItemRepository in OrderEntity, poiché si tratta di una violazione di diversi principi a cui posso pensare. Ma la fluidità della sintassi è qualcosa che vogliamo davvero, perché è facile da leggere e gestire, oltre che da test.
Considera il seguente codice, prendendo nota del metodo getLineItems
in OrderEntity
:
interface IOrderService {
public function getOrderByID($orderID) : OrderEntity;
public function getLineItems(OrderEntity $orderEntity) : LineItemCollection;
}
class OrderService implements IOrderService {
private $orderRepository;
private $lineItemRepository;
public function __construct(IOrderRepository $orderRepository, ILineItemRepository $lineItemRepository) {
$this->orderRepository = $orderRepository;
$this->lineItemRepository = $lineItemRepository;
}
public function getOrderByID($orderID) : OrderEntity {
return $this->orderRepository->getByID($orderID);
}
public function getLineItems(OrderEntity $orderEntity) : LineItemCollection {
return $this->lineItemRepository->getLineItemsByOrderID($orderEntity->ID());
}
}
class OrderEntity {
private $ID;
private $lineItems;
public function getLineItems(IOrderServiceInternal $orderService) {
if(!is_null($this->lineItems)) {
$this->lineItems = $orderService->getLineItems($this);
}
return $this->lineItems;
}
}
È questo il modo accettato di implementare la sintassi fluente nelle Entità senza violare i principi fondamentali di DDD e OOP? Per me sembra soddisfacente, poiché stiamo solo esponendo il livello di servizio, non il livello dell'infrastruttura (che è annidato all'interno del servizio)