Sono alle prese con il seguente problema. Diciamo che ho un componente che esegue operazioni su guest e room e utilizza un certo numero di interfacce astratte, sulla falsariga di:
class HotelManager
{
public HotelManager(IRoomsRepository rep, ILog log, ...);
public void PutGuestInRoom(string guest, int room, DateTime checkIn, int nights);
public void RemoveGuestFromRoom(string guest, int room);
public int GetSpentNights(string guest, int room);
}
I parametri "Guest" e "room" appaiono in ogni metodo. Se la logica è complicata, questi parametri, così come qualsiasi informazione correlata come GuestInfo
e RoomInfo
dovranno essere passati molto. Quindi, voglio creare un oggetto operazione che mantenga il contesto dell'operazione corrente nel suo stato:
class HotelRoomOperation
{
private string _guest;
private int _room;
private GuestInfo _guestInfo;
public HotelRoomOperation(string guest, int room, IRoomsRepository rep, ILog log, ...);
public void PutGuestInRoom(DateTime checkIn, int nights);
public void RemoveGuestFromRoom();
public int GetSpentNights();
}
Tuttavia, ora è difficile creare questo oggetto tramite l'integrazione delle dipendenze. Immagina di avere un codice come questo
class HotelManager
{
public void FillRoomWithGuests(int room, IEnumerable[string] guests) // angle brackets, anyone?
{
foreach (var guest in guests)
{
CreateHotelOperation(guest, room).PutGuestInRoom();
}
}
}
Come implemento CreateHotelOperation()
? Vedo diverse opzioni, tutte pessime:
-
Esplicitamente "nuovo" l'operazione. Ciò richiederà a HotelManager di conoscere e accettare tutte le dipendenze dell'operazione, che creerà un codice dettagliato, violerà il principio DRY e l'incapsulamento.
class HotelManager { public HotelManager(IRoomsRepository, ILog, ...); HotelRoomOperation CreateHotelOperation(string guest, int room) { // _roomRepository not used anywhere else! return new HotelRoomOperation(guest, room, _roomRepository, _log,...); } }
-
Non inserire parametri concreti nel costruttore di
HotelRoomOperation
e lasciare Unity resuscolarlo. Crea proprietà inHotelRoomOperation
da compilare al momento della creazione:class HotelManager { public HotelManager(Func<HotelOperation> createHotelOperation); HotelRoomOperation CreateHotelRoomOperation(string guest, int room) { var operation = _createHotelOperation(); operation.Room = room; operation.Guest = guest; return operation; } }
Questo è male, perché il costruttore di HotelRoomOperation crea un oggetto in uno stato inutilizzabile. Posso dimenticare di inizializzare una proprietà e questo porterà a un oggetto incompleto.
-
Simile al n. 2, ma abbiamo un inizializzatore esplicito su HotelRoomOperation che passa tutte le proprietà aggiuntive contemporaneamente:
class HotelManager { HotelRoomOperation CreateHotelOperation(string guest, int room) { var operation = _createHotelOperation().Init(guest, room); return operation; } } class HotelRoomOperation { public HotelRoomOperation(/* dependencies */ ); public HotelRoomOperation Init(string guest, int room) { _guest = guest; _room = room; return this; } }
Questa è probabilmente la migliore di tutte le opzioni, ma
HotelRoomOperation
costruttore ancora crea un oggetto in uno stato inutilizzabile, che è cattivo.
Qualche altra idea?