Personalmente non sono in un gruppo di persone che pensano che Entities
non debba accedere a Repositories
. Quindi per me, la risposta alla tua domanda è "Sì, certo, vai avanti".
Ma nel caso in cui tu non voglia farlo, vorrei cambiare leggermente la soluzione di Ewan.
// notice this is not general vehicle repository
public interface IVehicleReservationRepository
{
bool IsReserveAvailable();
}
public class Vehicle
{
// notice Reserve being private
// should only be called when reservation can happen
private void Reserve()
{
// do stuff ...
}
public class ReservationService
{
private IVehicleReservationRepository _vehicleReservationRepo;
public ReservationService(IVehicleReservationRepository vehicleReservationRepo)
{
_vehicleReservationRepo = vehicleReservationRepo;
}
public void Reserve(Vehicle v)
{
bool isReserveAvailable = _vehicleReservationRepo.IsReserveAvailable();
if (isReserveAvailable)
{
v.Reserve();
}
}
public void ReserveAll(IEnumerable<Vehicle> vehicles)
{
// efficient reservation for multiple vehicles
// doesn't need to call repository for every vehicle
}
}
}
Rendendo il RegistrationService
nidificato di Vehicle
, gli consente di accedere ai suoi membri privati. Questo perché rendere il servizio annidato all'entità li accoppia insieme. Quindi il servizio è parte integrante dell'entità. È ancora possibile utilizzare DI per creare il ReservationService
e averlo separato in questo modo rende chiaro quali operazioni fanno uso del servizio di repository.
Un'altra cosa da sottolineare è che invece di usare generico IVehicleRepository
, ho creato uno speciale IVehicleReservationRepository
, che è usato solo in questo caso d'uso. Alla fine, potrebbe essere implementato su VehicleRepository
, ma questo non è correlato a questo problema. Rendere l'interfaccia specifica per un caso d'uso è un buon utilizzo del principio di segregazione dell'interfaccia e renderebbe il test più semplice, poiché non è necessario preoccuparsi di altri metodi presenti nel repository completo.
L'ultima cosa che mi è venuta in mente è lo scenario, dove potresti voler prenotare più veicoli. Se avevi il metodo di riserva su un'entità, dovresti chiamarlo su ogni veicolo, chiamando il repository, e quindi il database, per ogni entità. Ma avere un servizio separato consente di ottimizzare questo chiamando il deposito una volta per più veicoli. Come visto nel metodo ReserveAll
su ReservationService
.