Fahrzeugvermietung
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 87 von 87.
Für diese abschließende Herausforderung wirst du ein Vehicle Rental Service-System bauen, das alle OOP-Konzepte zusammenführt, die du im Laufe dieses Kurses gemeistert hast.
Ihr System sollte eine Flotte verschiedener Fahrzeugtypen modellieren. Betrachten Sie eine Basisklasse Vehicle mit gemeinsamen Eigenschaften wie Kennzeichen, Marke und täglicher Mietrate. Subklassen wie Car, Motorcycle und Truck können diese um spezifische Attribute wie die Anzahl der Sitze, den Hubraum oder die Ladekapazität erweitern.
Interfaces können Mietverhalten definieren: Ein Rentable-Interface könnte Methoden wie rent(), returnVehicle() und calculateCost(int days) deklarieren. Verschiedene Fahrzeugtypen könnten Preisstrategien unterschiedlich implementieren, was dies zu einem perfekten Anwendungsfall für Polymorphismus macht.
Überlegen Sie, wie eine RentalAgency Klasse die Flotte mittels Komposition verwaltet.
Benutzerdefinierte Ausnahmen wie VehicleNotAvailableException können Sonderfälle behandeln.
Sie könnten das Factory-Pattern anwenden, um Fahrzeuge zu erstellen, oder Enums für Fahrzeugkategorien und den Mietstatus verwenden.
Diese Herausforderung testet Ihre Fähigkeit, ein vollständiges, gut strukturiertes OOP-System zu entwerfen. Viel Glück!
Aufgabe
EinfachLassen Sie uns einen vollständigen Fahrzeugvermietungsdienst aufbauen, der alles zusammenführt, was Sie über OOP gelernt haben! Sie erstellen ein System, das eine Flotte verschiedener Fahrzeugtypen verwaltet, Vermietungen mit ordnungsgemäßer Validierung abwickelt und ein Factory-Muster zur Erstellung von Fahrzeugen verwendet.
Sie werden Ihren Code über sieben Dateien organisieren:
RentalStatus.java: Erstellen Sie ein Enum, das den Mietstatus eines Fahrzeugs darstellt. Fügen Sie die WerteAVAILABLE,RENTEDundMAINTENANCEhinzu. Fügen Sie ein privates Felddescription(String), einen Konstruktor und einen Getter hinzu. Available sollte die Beschreibung "ready to rent" haben, rented sollte "currently in use" haben und maintenance sollte "under service" haben.VehicleNotAvailableException.java: Erstellen Sie eine benutzerdefinierte Exception, dieExceptionerweitert. Der Konstruktor sollte ein Kennzeichen akzeptieren und eine Nachricht im FormatVehicle not available: [licensePlate]erstellen.Rentable.java: Erstellen Sie ein Interface, das Mietoperationen definiert. Deklarieren Sie die Methodenrent(), die einen boolean zurückgibt,returnVehicle(), die einen boolean zurückgibt, undcalculateCost(int days), die einen double zurückgibt.Vehicle.java: Erstellen Sie eine abstrakte Basisklasse für alle Fahrzeuge. Fügen Sie private Felder fürlicensePlate(String),brand(String),dailyRate(double) undstatus(RentalStatus, initialisiert auf AVAILABLE) hinzu. Der Konstruktor nimmt licensePlate, brand und dailyRate entgegen. Fügen Sie entsprechende Getter und einen Setter für status hinzu. Deklarieren Sie eine abstrakte MethodegetVehicleType(), die einen String zurückgibt. Implementieren Sie einegetDetails()-Methode, die"[licensePlate] [brand] ([vehicleType]) - $[dailyRate]/day - [status description]"zurückgibt, wobei dailyRate auf 2 Dezimalstellen formatiert ist.Car.java: Erstellen Sie eine Klasse, die Vehicle erweitert und Rentable implementiert. Fügen Sie ein privates Feldseats(int) hinzu. Der Konstruktor nimmt licensePlate, brand, dailyRate und seats entgegen. Implementieren SiegetVehicleType()so, dass"Car"zurückgegeben wird. Fürrent(): Wenn der Status AVAILABLE ist, setzen Sie ihn auf RENTED und geben Sie true zurück; andernfalls geben Sie false zurück. FürreturnVehicle(): Wenn der Status RENTED ist, setzen Sie ihn auf AVAILABLE und geben Sie true zurück; andernfalls geben Sie false zurück. FürcalculateCost(int days)geben Sie dailyRate multipliziert mit days zurück.Motorcycle.java: Erstellen Sie eine Klasse, die Vehicle erweitert und Rentable implementiert. Fügen Sie ein privates FeldengineCC(int) hinzu. Der Konstruktor nimmt licensePlate, brand, dailyRate und engineCC entgegen. Implementieren SiegetVehicleType()so, dass"Motorcycle"zurückgegeben wird. Implementieren Sie die Rentable-Methoden auf die gleiche Weise wie bei Car, abercalculateCost()sollte einen Rabatt von 10 % anwenden (mit 0.9 multiplizieren).RentalAgency.java: Erstellen Sie eine Klasse, die die Fahrzeugflotte mithilfe einer ArrayList verwaltet. Fügen Sie folgende Methoden hinzu:addVehicle(Vehicle vehicle)- fügt ein Fahrzeug zur Flotte hinzufindVehicle(String licensePlate)- gibt das Vehicle oder null zurückrentVehicle(String licensePlate, int days)- findet das Fahrzeug, versucht es zu mieten (Casting zu Rentable) und gibt die Mietkosten zurück. Werfen Sie eineVehicleNotAvailableException, wenn das Fahrzeug nicht gefunden wird oder wenn rent() false zurückgibtreturnVehicle(String licensePlate)- findet und gibt das Fahrzeug zurück, gibt true bei Erfolg zurückgetAvailableVehicles()- gibt eine ArrayList von Fahrzeugen mit dem Status AVAILABLE zurück
Main.java: Bauen Sie Ihren Vermietungsdienst! Sie erhalten einen kommagetrennten String mit Befehlen:ADD_CAR:licensePlate:brand:dailyRate:seatsADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCCRENT:licensePlate:daysRETURN:licensePlateAVAILABLE
Verarbeiten Sie jeden Befehl und geben Sie Folgendes aus:
- ADD_CAR/ADD_MOTORCYCLE:
Added: [brand] ([vehicleType]) - RENT:
Rented [licensePlate] for [days] days - Total: $[cost](Kosten auf 2 Dezimalstellen), oderError: [exception message] - RETURN:
Returned: [licensePlate]oderReturn failed: [licensePlate] - AVAILABLE: Geben Sie
Available vehicles:aus, gefolgt von den Details jedes verfügbaren Fahrzeugs in separaten Zeilen
Geben Sie nach allen Befehlen
--- Fleet Summary ---aus, gefolgt von den Details jedes Fahrzeugs.
Sie erhalten eine Eingabe: den kommagetrennten Befehls-String.
Zum Beispiel bei der Eingabe ADD_CAR:ABC-123:Toyota:50.00:5,ADD_MOTORCYCLE:XYZ-789:Honda:40.00:600,RENT:ABC-123:3,RENT:ABC-123:2,AVAILABLE,RETURN:ABC-123 wäre Ihre Ausgabe:
Added: Toyota (Car)
Added: Honda (Motorcycle)
Rented ABC-123 for 3 days - Total: $150.00
Error: Vehicle not available: ABC-123
Available vehicles:
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rent
Returned: ABC-123
--- Fleet Summary ---
ABC-123 Toyota (Car) - $50.00/day - ready to rent
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rentDiese Herausforderung kombiniert Vererbung (Vehicle-Hierarchie), Interfaces (Rentable), Enums (RentalStatus), benutzerdefinierte Exceptions, Polymorphismus (einheitliche Behandlung verschiedener Fahrzeugtypen) und Komposition (RentalAgency verwaltet Fahrzeuge) zu einem vollständigen Vermietungssystem!
Spickzettel
Diese abschließende Herausforderung kombiniert mehrere OOP-Konzepte zu einem vollständigen System. Hier sind die wichtigsten Muster und Techniken:
Enums mit Feldern
Enums können Felder, Konstruktoren und Methoden haben:
public enum RentalStatus {
AVAILABLE("ready to rent"),
RENTED("currently in use");
private String description;
private RentalStatus(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}Benutzerdefinierte Exceptions
Erstellen Sie domänenspezifische Exceptions, indem Sie Exception erweitern:
public class VehicleNotAvailableException extends Exception {
public VehicleNotAvailableException(String licensePlate) {
super("Vehicle not available: " + licensePlate);
}
}Abstrakte Basisklassen mit Interfaces
Kombinieren Sie abstrakte Klassen für die gemeinsame Implementierung mit Interfaces für Verhaltensverträge:
public abstract class Vehicle {
private String licensePlate;
private RentalStatus status;
public abstract String getVehicleType();
public String getDetails() {
return licensePlate + " " + getVehicleType() + " - " + status.getDescription();
}
}
public interface Rentable {
boolean rent();
boolean returnVehicle();
double calculateCost(int days);
}
public class Car extends Vehicle implements Rentable {
public boolean rent() {
if (getStatus() == RentalStatus.AVAILABLE) {
setStatus(RentalStatus.RENTED);
return true;
}
return false;
}
}Komposition zur Verwaltung
Verwenden Sie Komposition, um Sammlungen von Objekten zu verwalten:
public class RentalAgency {
private ArrayList<Vehicle> fleet = new ArrayList<>();
public void addVehicle(Vehicle vehicle) {
fleet.add(vehicle);
}
public double rentVehicle(String licensePlate, int days) throws VehicleNotAvailableException {
Vehicle vehicle = findVehicle(licensePlate);
if (vehicle == null) {
throw new VehicleNotAvailableException(licensePlate);
}
Rentable rentable = (Rentable) vehicle;
if (!rentable.rent()) {
throw new VehicleNotAvailableException(licensePlate);
}
return rentable.calculateCost(days);
}
}Polymorphismus in Aktion
Verschiedene Unterklassen können Interface-Methoden unterschiedlich implementieren:
// Auto: Standardpreisgestaltung
public double calculateCost(int days) {
return dailyRate * days;
}
// Motorrad: ermäßigte Preisgestaltung
public double calculateCost(int days) {
return dailyRate * days * 0.9;
}Probier es selbst
import java.util.Scanner;
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Erstelle eine RentalAgency-Instanz
// TODO: Trenne die Eingabe durch Kommas, um einzelne Befehle zu erhalten
// TODO: Verarbeite jeden Befehl:
// ADD_CAR:licensePlate:brand:dailyRate:seats -> gib "Added: [brand] ([vehicleType])" aus
// ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC -> gib "Added: [brand] ([vehicleType])" aus
// RENT:licensePlate:days -> gib "Rented [licensePlate] for [days] days - Total: $[cost]" aus (2 Dezimalstellen)
// oder "Error: [exception message]", falls eine Exception geworfen wird
// RETURN:licensePlate -> gib "Returned: [licensePlate]" oder "Return failed: [licensePlate]" aus
// AVAILABLE -> gib "Available vehicles:" aus, gefolgt von den Details jedes verfügbaren Fahrzeugs
// TODO: Gib nach allen Befehlen "--- Fleet Summary ---" aus
// gefolgt von den Details jedes Fahrzeugs
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem