Non hai bisogno di una mappatura uno-a-uno di interattori ed entità. Credo che un tale design sarebbe dannoso.
Il DDD riguarda esclusivamente i limiti di contesto e il linguaggio ubiquo all'interno di quei confini. Quando ti concentri davvero sulla creazione di oggetti per rappresentare la lingua del business, scoprirai che tutto inizia a modellarsi in modo un po 'diverso.
Mi sembra strano che una vendita possa creare o spedire se stessa. Nel mondo reale, potrei immaginare un venditore che fa una vendita. Quindi, un reparto spedizioni può gestire la logistica per spedirlo. Forse, una vendita sarebbe creata tramite un carrello della spesa on-line e spedita via e-mail. Usando questo linguaggio come esempio, esploriamo un possibile design alternativo.
SalesPerson
+createSale(Customer, Product, Price)
+amendSale(Sale, Amendment)
ShippingDepartment
+shipSale(Sale)
Aspetta un secondo !? Di solito non spediamo ordini? Forse dovrebbe andare così:
SalesPerson
+createOrder(Customer, Product, Price)
+amendOrder(Order, Amendment)
ShippingDepartment
+shipOrder(Order)
Order
+constructor(Customer, Product, Price)
+applyDiscount(Discount)
+updateShippingAddress(Address)
Entrambi si stanno avvicinando, ma in realtà il nostro team di vendita non li chiama ordini e il nostro reparto spedizioni li chiama solo ordini. Inoltre, gli ordini vengono sempre creati dall'esistenza di una vendita, quindi dovremmo riflettere anche questo.
SalesPerson
+createSale(Customer, Product, Price)
+amendSale(Sale, Amendment)
Sale
+constructor(Customer, Product, Price)
+applyDiscount(Discount)
+updateShippingAddress(Address)
ShippingDepartment
+shipOrder(Order)
Order
+constructor(Sale)
+placeOnHold()
+shipped(TrackingNumber)
E così, continua a svilupparsi.
Il modo in cui gestisco la separazione della logica è provare a visualizzare quell'oggetto nella vita reale. Quindi, pensa alle proprietà e alle azioni che sono rilevanti per il business-need / use-case / feature.
Modifica: come interagisci con i metodi su un'entità in DDD?
Invece di usare il pattern Command o altri interattori, puoi semplicemente usarli direttamente:
salesPerson = new SalesPerson()
sale = salesPerson.createSale(...)
...
shippingDept.shipOrder(new Order(sale))
Ricorda che i due non si escludono a vicenda. Puoi ancora utilizzare un pattern Command o Use Case / interactors se ce n'è bisogno. Potresti avere qualcosa di simile a questo (1 interactor per molte entità e metodi):
PartyUseCase(ShippingDepartment)
+prepareParty(SalesPerson, Customer)
plates = ProductRepo.findByName('plates')
forks = ProductRepo.findByName('forks')
platesSale = salesPerson.createSale(Customer, plates)
forksSale = salesPerson.createSale(Customer, forks)
ShippingDepartment.shipOrder(new Order(platesSale))
ShippingDepartment.shipOrder(new Order(forksSale))
...
In alternativa, potrebbe esserci uno script semplice che viene eseguito una volta al giorno con nient'altro che questo (0interpreti):
orderRepo = new OrderRepository()
shippingDept = new ShippingDepartment()
for each order in orderRepo.getOrdersToShip()
shippingDept.shipOrder(order)
In definitiva, se stai creando una mappatura uno-a-uno delle classi ai metodi, stai creando una complessità non necessaria.