IoC, Unity: creazione di un componente con parametri concreti aggiuntivi

3

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:

  1. 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,...);
         }
    }
    
  2. Non inserire parametri concreti nel costruttore di HotelRoomOperation e lasciare Unity resuscolarlo. Crea proprietà in HotelRoomOperation 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.

  3. 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?

    
posta Ivan Krivyakov 11.06.2016 - 20:42
fonte

1 risposta

1

Stai lasciando hotelRoomOperation in uno stato inutilizzabile perché hai messo insieme due oggetti diversi e li hai chiamati hotelRoomOperation . Non sei pronto per il secondo da inizializzare, quindi attendi. Mentre aspetti, sei inutilizzabile.

Ogni oggetto dovrebbe avere una sola responsabilità. In questo modo esistono solo quando possono essere utilizzati per adempiere a tale responsabilità. Dovrebbero anche avere un buon nome che rifletta questa responsabilità. hotelRoomOperation suona come se potesse fare qualsiasi cosa, dall'avere la stanza pulita alla rimozione dei reni nella vasca da bagno.

Se si desidera ridurre la tensione passando coppie di camere ospiti, considerare il modello dell'oggetto parametro. Dagli un nome significativo come occupante.

Vedo molti casi d'uso che non stai supportando. A volte un ospite prenota più stanze. A volte un ospite prenota una stanza ma ha più ospiti con loro ma non condivide le loro informazioni. A volte ti danno le informazioni di tutti in modo che chiunque possa richiedere le chiavi di sostituzione. A volte un ospite prenota una stanza particolare prima del check-in. Fino a te vuoi che tu voglia sostenere. Basta essere consapevoli di ciò che non sei.

    
risposta data 13.06.2016 - 02:28
fonte

Leggi altre domande sui tag