OOP-Designproblem. Zwei Arten von leer Optional

8

Ich schreibe eine recht einfache Anwendung, die sich mit der Reservierung von Hotelzimmern befasst. Ich habe irgendwann ein Problem.

Ich bearbeite eine Warteschlange mit Bestellungen. Für jede Bestellung sollte einer der Rezeptionisten ein Zimmer (eines oder keines) für den Kunden gemäß seiner Strategie auswählen. Deshalb habe ich mich für Java entschieden Optional. Das Problem ist, dass die Bestellung storniert werden sollte, wenn zum gewünschten Datum einfach keine freien Zimmer vorhanden sind. Wenn jedoch einige Zimmer verfügbar sind und keines der Strategie der Rezeptionistin entspricht, sollte die Bestellung wieder in die Warteschlange gestellt werden.

Die Auswahl der Zimmer sollte auf jeden Fall die Pflicht der Rezeption sein. Was ist Ihrer Meinung nach der beste Weg, um dieses Problem auf saubere Weise zu lösen? Sollte ich eine Ausnahme auslösen, anstatt leer zurückzukehren, Optionalwenn derzeit keine Zimmer vorhanden sind? Leider sind Ausnahmen normalerweise keine gute Lösung für die Steuerung des Codeflusses.

Codefragment:

    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);
    }
Paweł Koniarski
quelle
1
Was nützt es, die Bestellung wieder in die Warteschlange zu stellen? Wird der Empfang nicht immer und immer wieder ausfallen?
Winston Ewert
@WinstonEwert Nein. Es gibt viele Rezeptionisten, die sich mit Bestellungen befassen, und sie haben unterschiedliche Auswahlstrategien.
Paweł Koniarski
@ WinstonEwert Ich würde davon ausgehen, dass dies der Fall ist, bis sich der Zustand des Hotels ändert.
candied_orange
@ PawełKoniarski bitte definieren Sie 'Strategie' in diesem Zusammenhang
candied_orange
1
Ja, genau so. Die Rezeptionisten werden in einem Zyklus durchgeschleift und jede nächste Bestellung wird von einer anderen Rezeptionistin bedient.
Paweł Koniarski

Antworten:

1

Ich denke, Sie könnten es auf zwei Arten modellieren:

Option 1: Verwenden eines Wrappers + einer Aufzählung für die Antwort der Empfangsdame:

enum ReceptionistDecision {
    BOOK_ROOM,
    NO_ROOM,
    RETURN_TO_QUEUE,
}

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

    ReceptionistResponse(Room room) {
        ...
    }

    ReceptionistResponse(ReceptionistDecision decision) {
        ...
    }
}

Option 2: Oder Sie können eine Schnittstellenklasse erstellen und jede der Antworten von dieser erben. Etwas wie:

interface class ReceptionistResponse {

}

class ReturnToQueueReceptionistResponse implements ReceptionistResponse {

}

class NoRoomsBookedQueueReceptionistResponse implements ReceptionistResponse {

}

class RoomBookedReceptionistResponse implements ReceptionistResponse {
    Room BookedRoom;
}

Die chooseRoomMethode wäre:

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);
    }
}

Und der Client-Code für Option 1:

ReceptionistResponse response = receptistist.chooseRoom (Zimmer, order.getQuestionnaire ());

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

    orders.add(order);
}
RMalke
quelle
Ich habe mich für etwas entschieden, das Ihrer ersten Option nahe kommt. Vielen dank für Deine Hilfe.
Paweł Koniarski
5

Es gibt einige Ansätze, die man anwenden könnte, um dies zu modellieren.

Erstens könnten wir die passive Empfangsdame haben. Die passive Empfangsdame entscheidet, was zu tun ist, tut aber nichts. Stattdessen haben wir so etwas wie Unterricht

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

Sie werden vielleicht feststellen, dass dies die gleiche Grundidee wie optional ist, aber wir haben sie auf drei Optionen anstatt nur auf eine erweitert. Jede statische Methode erstellt eine bestimmte Antwort und gibt diese zurück. Dann hat Ihre Rezeptionistin eine Methode

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

Der aufrufende Code nimmt die ReceptionistResponse entgegen und übernimmt die erforderliche Antwort.

Alternativ haben Sie möglicherweise eine aktive Empfangsdame. Die aktive Empfangsdame führt tatsächlich die folgenden Aktionen aus:

void attemptBookOrder(Order order) {
    if (rooms.allRoomsAreFull()) {
       order.cancel();
    }
    if (...) {
       order.bookRoom(room);
    } else {
       orderQueue.put(order);
    }
}
Winston Ewert
quelle
Wie würden Sie die ReceptionistResponse strukturieren, um die drei möglichen Antworten zu behandeln? Eine Aufzählung plus ein optionales Raumfeld? Was ist mit einem Fall, in dem die unterschiedlichen Antworten jeweils zahlreiche Eigenschaften hatten (z. B. prozentual übereinstimmend oder Zimmer verfügbar)?
AmadeusDrZaius
1
@AmadeusDrZaius, Sie können entweder die Aufzählung mit optionalen oder mehreren Unterklassen verwenden.
Winston Ewert
1

Die Rückgabe der Option scheint in Ordnung zu sein, aber wenn kein Wert vorhanden ist, sollte die Logik nicht fortgesetzt werden. Jedem Gast ist ein richtiges Zimmer zugewiesen oder er ist kein Gast. Sobald sich die Rezeptionistin entschlossen hat, eine leere Option zurückzugeben, sollte die Bestellung wieder in die Warteschlange gestellt werden und nicht mehr.

Es ist in Ordnung, zuerst die Bestellung aus der Warteschlange zu übernehmen und dann die Datei Empfangspersonal.chooseRoom auszuführen. Wenn sie leer ist, fügen Sie die Bestellung erneut zum Ende der Warteschlange hinzu. Ich würde das in einen Versuch einwickeln, um sicherzustellen, dass keine Bestellungen verloren gehen.

Wenn ein Raum ausgewählt wird, sollte er als Raum und nicht als optional fortgeführt werden. Optional sollte nur als temporäre Variable verwendet werden, da der einzige Zweck darin besteht, festzustellen, dass die Empfangsdame beschlossen hat, die Bestellung vorerst nicht zu bearbeiten.

Martin Maat
quelle