Problema di progettazione OOP. Due tipi di vuoto Opzionale

9

Sto scrivendo un'applicazione abbastanza semplice che si occupa della prenotazione delle camere d'albergo. Ho un problema in una fase.

Sto elaborando una coda di ordini. Per ogni ordine uno dei receptionist dovrebbe scegliere una stanza (una o nessuna) per il cliente secondo la sua strategia. Ecco perché ho deciso di andare con Java Optional . Il problema è che se non ci sono semplicemente stanze libere alla data desiderata l'ordine dovrebbe essere cancellato, ma se ci sono alcune camere disponibili e nessuna di queste è adatta alla strategia del receptionist, l'ordine dovrebbe essere rimesso in coda.

Scegliere le stanze sicuramente dovrebbe essere il dovere del receptionist. Quale pensi che sia il modo migliore per affrontare quel problema in modo pulito? Devo lanciare un'eccezione invece di restituire Optional vuota quando non ci sono date alla data? Sfortunatamente, le eccezioni di solito non sono una buona soluzione per controllare il flusso del codice.

Frammento di codice:

    Optional<Room> selectedRoom = receptionist.chooseRoom(rooms, 
                                                          order.getQuestionnaire());

    boolean decision = selectedRoom
            .map(room -> receptionist.askClient(order.getClient(), 
                                                room,
                                                order.getQuestionnaire()))
            .orElse(false);

    if (shouldProcessAgain(order, selectedRoom.isPresent(), decision)) {
        orders.add(order);
    }
    
posta Paweł Koniarski 23.04.2016 - 01:35
fonte

3 risposte

1

Penso che potresti modellarlo in due modi:

Opzione 1: Utilizzo di un wrapper + enum per la risposta del receptionist:

enum ReceptionistDecision {
    BOOK_ROOM,
    NO_ROOM,
    RETURN_TO_QUEUE,
}

class ReceptionistResponse {
    ReceptionistDecision Decision;
    Optional<Room> Room;

    ReceptionistResponse(Room room) {
        ...
    }

    ReceptionistResponse(ReceptionistDecision decision) {
        ...
    }
}

Opzione 2: oppure potresti utilizzare una classe di interfaccia e far sì che ognuna delle risposte sia ereditata da essa. Qualcosa come:

interface class ReceptionistResponse {

}

class ReturnToQueueReceptionistResponse implements ReceptionistResponse {

}

class NoRoomsBookedQueueReceptionistResponse implements ReceptionistResponse {

}

class RoomBookedReceptionistResponse implements ReceptionistResponse {
    Room BookedRoom;
}

Il metodo chooseRoom sarebbe:

ReceptionistResponse chooseRoom(List<Rooms> allRooms, Questionnaire questionnaire) {
    if (/* all rooms are full */) {
        // Option 1
        return new ReceptionistResponse(ReceptionistDecision.RETURN_TO_QUEUE);

        // Option 2
        return new ReturnToQueueReceptionistResponse();
    }

    if (/* Choose no rooms */) {
        // Option 1
        return new ReceptionistResponse(ReceptionistDecision.NO_ROOM);

        // Option 2
        return new NoRoomsBookedQueueReceptionistResponse();
    }

    if (/* Choose some room */) {
        // Option 1
        return new ReceptionistResponse(choosenRoom);

        // Option 2
        return new RoomBookedReceptionistResponse(choosenRoom);
    }
}

E il codice cliente per l'opzione 1:

ReceptionistResponse response = receptionist.chooseRoom (rooms, order.getQuestionnaire ());

// options 1
if (response.Decision == ReceptionistDecision.RETURN_TO_QUEUE) {
// option 2
if (response instanceof(ReturnToQueueReceptionistResponse)) {

    orders.add(order);
}
    
risposta data 23.04.2016 - 02:50
fonte
5

Ci sono un paio di approcci che si potrebbero applicare per modellarlo.

In primo luogo, potremmo avere il receptionist passivo. Il receptionist passivo decide cosa fare, ma non fa nulla. Invece, abbiamo classe qualcosa come

public class ReceptionistResponse {
    public static ReceptionistResponse bookRoom(Room room);
    public static ReceptionistResponse cancelOrder();
    public static ReceptionistResponse returnToQueue();
}

Ora, potresti notare che questa è la stessa idea di base di quella facoltativa, ma l'abbiamo estesa a tre opzioni invece di una sola. Ogni metodo statico crea e restituisce una risposta particolare. Quindi il tuo receptionist ha un metodo

ReceptionistReponse attemptBookOrder(Order order) {
    ...
    return ReceptionistResponse.bookRoom(room);
    ...
}

Il codice chiamante accetta ReceptionistResponse e intraprende la risposta necessaria.

In alternativa, potresti avere una receptionist attiva. La receptionist attiva esegue effettivamente le azioni:

void attemptBookOrder(Order order) {
    if (rooms.allRoomsAreFull()) {
       order.cancel();
    }
    if (...) {
       order.bookRoom(room);
    } else {
       orderQueue.put(order);
    }
}
    
risposta data 23.04.2016 - 02:04
fonte
1

Il ritorno dell'Optional sembra OK ma se non c'è valore la logica non dovrebbe procedere. Ad ogni ospite è assegnata una stanza reale o non è un ospite. Quindi, una volta che l'addetto alla reception ha deciso di restituire un Opzionale vuoto, l'ordine dovrebbe essere rimesso in coda e niente di più.

Va bene prima prendere l'ordine dalla coda, quindi eseguire receptionist.chooseRoom e se torna vuoto, aggiungere nuovamente l'ordine a (la fine della) coda. Lo concluderei in un tentativo, infine, per assicurarmi che nessun ordine si perda.

Se una stanza viene selezionata, dovrebbe procedere come una stanza, non come Facoltativa. Opzionale dovrebbe essere usato come variabile temporanea solo perché il suo unico scopo è quello di rilevare che l'addetto alla reception ha deciso di non gestire l'ordine per il momento.

    
risposta data 23.04.2016 - 07:49
fonte

Leggi altre domande sui tag