Input/Output Zwischen zwei ID-Räumen unterscheiden und Objekt löschen

DagobertDuck

Bekanntes Mitglied
Ich arbeite derzeit an einem Projekt zur Eisenbahnsimulation. RollingStock (Rollmaterial) ist die Oberklasse und Coach (Wagen), Engine (Lokomotive) und TrainSet (Triebzug) sind Unterklassen von RollingStock.

- Alle Wagen haben eine eindeutige ganzzahlige aufsteigende ID, die bei 1 beginnt.
- TrainSets und Engines teilen sich ihren ID-Raum. Diese ID besteht aus einer Baureihe (series) und einem Namen (name) (beides Strings).

Nun muss ich den Befehl delete rolling stock <id> implementieren.
Das Rollmaterial wird durch seine eindeutige ID identifiziert. Bei einem Wagen wird der ID ein W vorangestellt. Die Eingabe der ID für TrainSets/Engines ist <series>-<name>.

Beispiele für eine gültige Benutzereingabe wären also
- delete rolling stock W42, Coach mit der ID 42 wird gelöscht,
- delete rolling stock ICE-1106, TrainSet oder Engine mit der Baureihe ICE und dem Namen 1106 wird gelöscht.

Wie bei allen anderen meiner Befehlen habe ich wie folgt begonnen:

Java:
public class DeleteRollingStockCommand extends Command {
    private static final Pattern PATTERN = Pattern.compile(
            String.format("delete rolling stock%s(?<id>%s)", InOutputStrings.COMMAND_SEPARATOR,
                    InOutputStrings.ROLLING_STOCK_ID_PATTERN));
    private String[] id;
    
    @Override
    public void execute() {
        try {
            // TODO: Rollmaterial mit angegebener ID löschen
            // RollingStock rollingStock = register.getRollingStock(id);
            // register.removeRollingStock(rollingStock);
            Terminal.printLine(InOutputStrings.OK);
        } catch (InvalidInputException e) {
            Terminal.printError(e.getMessage());
        }
    }
    
    @Override
    void setArguments(String argument) {
        Matcher matcher = PATTERN.matcher(argument);
        // TODO: Methode parseRollingStockId() programmieren
        // id = parseRollingStockId(matcher.group("id"));
    }
(COMMAND_SEPARATOR = " ", ROLLING_STOCK_ID_PATTERN = "([W]+?[0-9]+)|(\w+-\w+)")

Ich bin mir leider unsicher, wie ich diesen Befehl am geschicktesten implementieren kann.

Damit ihr etwas mehr die Struktur meines Codes versteht:

Coaches, TrainSets und Engines werden wie folgt gespeichert:

private final Map<Integer, Coach> coaches;

private final List<Engine> engines;
private final List<TrainSet> trainSets;

Code:
private final Map<Integer, Coach> coaches;

private final List<Engine> engines;

private final List<TrainSet> trainSets;

    public MyClassName() {
        this.coaches = new TreeMap<>();
        this.engines = new ArrayList<>();
        this.trainSets = new ArrayList<>();
    }
 

mihe7

Top Contributor
Wichtig sind zwei Dinge. Den ersten hast Du schon genannt:
Das Rollmaterial wird durch seine eindeutige ID identifiziert.
Eine ID ist einfach etwas, das ein Objekt eindeutig identifiziert, ob sich diese aus anderen Daten zusammensetzt, spielt keine Rolle.

Der zweite Punkt wäre, woraus das Rollmaterial entfernt werden soll. Wenn Du das weißt, kannst Du der betreffenden Klasse eine entsprechende Methode spendieren, die als Parameter eben die ID erhält.
 

DagobertDuck

Bekanntes Mitglied
Danke für die Antwort. Allerdings geht es mir eigentlich eher um die Verarbeitung der Benutzereingabe, also wie zwischen den eingegebenen IDs unterschieden werden kann. Außerdem soll dann das W entfernt werden, der String in ein integer umgewandelt werden bzw. die ID in zwei Strings aufgeteilt werden (series, name). Wie ich das genau machen soll ist mir unklar, insbesondere welcher Datentyp geeignet wäre.
 

mihe7

Top Contributor
Allerdings geht es mir eigentlich eher um die Verarbeitung der Benutzereingabe, also wie zwischen den eingegebenen IDs unterschieden werden kann.
OK, ich habe das vielleicht nicht deutlich genug formuliert. Die Unterscheidung in W<zahl> und <series>-<name> misst der ID eine Bedeutung zu. Eine ID hat aber keine Bedeutung, es ist einfach irgendein String. Ein RollingStock ist etwas, das eine ID besitzt, fertig.

Aus dem Bauch raus (kann Fehler enthalten):
Java:
public class RollingStockRepository {
    Map<String, RollingStock> stocks = new HashMap<>();

    public void add(RollingStock rs) { stocks.put(rs.getId(), rs); }
    public void delete(String id) { stocks.remove(id); }

    public <T extends RollingStock> get(String id, Class<T> clazz) {
        RollingStock rs = stocks.get(id);
        if (rs != null && clazz.isInstance(rs)) { 
            return clazz.cast(rs);
        }
        return null; // oder Exception
    }
}

Um Deine Frage trotzdem zu beantworten:
Java:
if (str.contains("-")) {
     // str muss der Form <series>-<name> entsprechen
} else if (str.startsWith("W")) {
     // str muss der Form W<zahl>entsprechen
     int wagonId = Integer.parseInt(str.substring(1));
}

bzw. die ID in zwei Strings aufgeteilt werden (series, name)
Wozu das denn?
 

DagobertDuck

Bekanntes Mitglied

Da der Konstruktor von Coach momentan so aussieht Coach(int id, int length, ...) und der Konstruktor von TrainSet und Engine folgendermaßen aussieht TrainSet(String series, String name, int length, ...) bzw. Engine(String series, String name, int length, ...). RollingStock besitzt also gar keine ID, sondern nur die Unterklassen. Das liegt daran, dass es zwei verschiedene ID-Räume gibt.
Um dann überprüfen zu können, ob die ID überhaupt existiert, muss ich zuerst den String in Series und Name teilen.

Eine eigene Map nur für RollingStock habe ich außerdem auch nicht.
Ist meine jetzige Modellierung ausbaufähig, und wie gehe ich das Problem dann am besten an?
 
Zuletzt bearbeitet:

mihe7

Top Contributor
RollingStock besitzt also gar keine ID, sondern nur die Unterklassen. Das liegt daran, dass es zwei verschiedene ID-Räume gibt.
Die Räume spielen genauso wenig eine Rolle wie die Konstuktoren: RollingStock beschreibt etwas, das identifizierbar ist.

Möglichkeit 1:
Java:
abstract class RollingStock {
    ...
    abstract String getId();
}

Möglichkeit 2:
Java:
abstract class RollingStock {
    private String id;

    protected RollingStock(String id) { this.id = id; }
  
    public String getId() { return id; }
}

In z. B. Coach:
Java:
class Coach extends RollingStock {
    private int coachNo;
     public Coach(int coachNo, int length, ...) {
         super("W" + coachNo); // Möglichkeit 2
         this.coachNo = coachNo;
         // ...
     }

     // Möglichkeit 1
    @Override
    public String getId() {
         return "W" + coachNo;
    }
}
 

DagobertDuck

Bekanntes Mitglied
Es sieht bei mir jetzt so aus:

Java:
public abstract class Coach extends RollingStock {
    private final int id;

    public Coach(..., int id) {
        super(...);
        this.id = id;
    }

    public String getId() {
        return Integer.toString(id);
    }
}

und


Java:
public abstract class Engine extends RollingStock {
    private String series;
    private String name;

    public Engine(..., String series, String name) {
        super(...);
        this.series = series;
        this.name = name;
    }

    public String getSeries() {
        return series;
    }

    public String getName() {
        return name;
    }

    public String getId() {
        return series + "-" + name;
    }
}

Analog für TrainSet.

Jetzt frage ich mich allerdings wie die execute() Methode des Befehls auszusehen hat.

Java:
    @Override
    public void execute() {
        if (id.startsWith("W")) {
            ...
        } else if (id.contains("-")) {
           ...
        }
    }

Was ist z. B. wenn die Baureihe (series) mit "W" anfängt? Und wie bekomme ich jetzt das RollingStock mit dieser ID?
For each Schleife über RollingStock geht nicht, da ich wie gesagt nur folgende Listen/Maps habe:

Java:
    private final Map<Integer, Coach> coaches;
    private final List<Engine> engines;
    private final List<TrainSet> trainSets;
 

mrBrown

Super-Moderator
Mitarbeiter
Sind die drei Listen/Maps so vorgegeben?


Du kannst einfach "blind" aus allen dreien löschen. Wenn du versuchst, den Coach aus engines zu löschen, passiert halt einfach nichts, erst wenn du den Coach aus coaches löscht, wird es auch gelöscht (und analog zu allen anderen).

Mit der ID selber solltest du im Idealfall nichts machen - das ist einfach nur ein String wie der aufgebaut ist, ist völlig egal.


Es sieht bei mir jetzt so aus:

Java:
public abstract class Coach extends RollingStock {
    private final int id;

    public Coach(..., int id) {
        super(...);
        this.id = id;
    }

    public String getId() {
        return Integer.toString(id);
    }
}
Die ID sollte doch mit "W" beginnen?
 

DagobertDuck

Bekanntes Mitglied
Ich glaube ich habe etwas für Verwirrung gesorgt.

Die ID soll nur bei der Benutzereingabe mit "W" beginnen. Wenn allerdings z. B. der Befehl "list coaches" aufgerufen wird, soll die ID ohne "W" ausgegeben werden.

Problematisch wird es dann auch mit dem createCoach Befehl. Momentan wird ein Wagen hier abgelegt Map<Integer, Coach> coaches.
Java:
    public void createCoach(Coach coach) {
        this.coaches.put(coach.getId(), coach);
    }

Leider bin ich etwas ungewiss, wie ich jetzt weiter machen soll...
 

DagobertDuck

Bekanntes Mitglied
Das ist aber doch nicht schön. Außerdem funktionieren dann all meine anderen Methoden wie z. B. getNextId() nicht mehr. Kann man den Command nicht schöner lösen? Also so, dass Coach immer noch int id und TrainSet/Engine String series, String name als Attribute haben.
 

DagobertDuck

Bekanntes Mitglied
@mihe7 OK. Wäre es also sinnvoller eine einzige Map<String, RollingStock> rollingStock zu erstellen, in der Coaches, TrainSets und Engines gespeichert werden? Dann frage ich mich allerdings, wie ich z. B. beim "list coaches" Befehl nur Coaches ausgeben soll.

Dadurch wäre die Implementierung des "delete rolling stock <id>" und des "add <trainID> <rollingStockID>" Befehls deutlich einfacher.
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Wäre es also sinnvoller eine einzige Map<String, RollingStock> rollingStock zu erstellen, in der Coaches, TrainSets und Engines gespeichert werden?
Das wäre damit zumindest möglich, muss aber nicht unbedingt sein. Wichtig war, dass die IDs aller RollingStock-Objekte vom selben Typ sind. Damit entfällt die lästige Unterscheidung, was die ID betrifft. Die Map wäre nur ein "Index", um anhand des (nun einheitlichen) Schlüssels an das betreffende Objekt zu kommen.

Dann frage ich mich allerdings, wie ich z. B. beim "list coaches" Befehl nur Coaches ausgeben soll.
Zum Beispiel, indem Du die Elemente des gesuchten Typs rausfilterst oder zusätzliche Listen verwaltest.

Die Filter-Variante würde im RollingStockRepository aus Kommentar #4 so aussehen:
Java:
public <T extends RollingStock> List<T> findByType(Class<T> type) {
    return stock.values().stream()
        .filter(e -> e.getClass().equals(type))
        .map(clazz::cast)
        .collect(Collectors.toList());
}

Damit kannst Du über das Repository nun RollingStock-Objekte hinzufügen, anhand ihrer ID löschen und nach Typ auflisten:
Java:
RollingStockRepository repos = new RollingStockRepository();
repos.add(new Coach(...));
// ...
List<Coach> coaches = repos.findByType(Coach.class);
 

DagobertDuck

Bekanntes Mitglied
OK, vielen Dank. Ich habe jetzt erstmal RollingStock und seinen Unterklassen das Attribut String id hinzugefügt.

Die drei Listen werde ich allerdings behalten und nicht eine einzige Liste für RollingStock benutzen.

Bei manchen Befehlen muss ich die Baureihe und den Namen eines TrainSets / einer Engine getrennt ausgeben.

Wenn ich .split("-") benutze kann es auch zu Fehlern kommen, da series und name jeweils auch das Zeichen "-" enthalten dürfen.

Wie kann ich nun folgende Methoden implementieren?

Java:
    public String getSeries() {
         ...
        return series;
    }

    public String getName() {
        ...
        return name;
    }

Gibt es denn keinen anderen Weg, ohne RollingStock eine id zu geben? Es ist doch schöner, wenn Coach direkt eine id vom Typ Integer hat und TrainSet/Engine getrennt String series und String name besitzen..
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Du brauchst kein extra Attribut für die ID, ein Getter dafür reicht.
In dem Getter kannst du die ID notfalls passendes zusammenbauen, zB aus series und Name, die normale Attribute bleiben können.
 

mihe7

Top Contributor
Es ist doch schöner, wenn Coach direkt eine id vom Typ Integer hat und TrainSet/Engine getrennt String series und String name besitzen..
Coach hat eine Wagennummer, die vom Typ int sein kann und TrainSet/Engine haben z. B. series und name als Attribute; beide haben eine ID vom Typ String.

Wie das ginge, habe ich zwar in Kommentar #6 schon gezeigt aber mal konkreter für beides:

Java:
abstract class RollingStock {
    ...
    abstract String getId();
}

Java:
class Coach extends RollingStock {
     private final int coachNo;

     public Coach(int coachNo, int length, ...) {
         super(...);
         this.coachNo = coachNo;
     }

    public int getCoachNo() { return coachNo; }

    @Override
    public String getId() {
         return "W" + coachNo;
    }
}

Java:
class TrainSet extends RollingStock {
     private final String series;
     private final String name;

     public Coach(String series, String name, int length, ...) {
         super(...);
         this.series = series;
         this.name = name;
     }

    public String getName() { return name; }
    public String getSeries() { return series; }

    @Override
    public String getId() {
         return series + "-" + name;
    }
}
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
O Text aus einer Textdatei rausholen, der zwischen zwei Schlüsselworten steht Allgemeine Java-Themen 4
Zrebna Random Number - Generische Formel zwischen zwei INKLUSIVEN Werten Allgemeine Java-Themen 16
D Best Practice Die niedrigste Differenz zwischen zwei Listen ermitteln. Allgemeine Java-Themen 10
J Fahrroute zwischen zwei Punkten finden Allgemeine Java-Themen 1
J Transfer von Integer zwischen zwei Clients - RMI Allgemeine Java-Themen 4
G Liste zwischen zwei Kalenderdaten erstellen Allgemeine Java-Themen 3
H RegularExpression zwischen zwei Strings Allgemeine Java-Themen 2
K Objekt-Austausch zwischen zwei Programmen über System-Clipboard Allgemeine Java-Themen 5
H Datenaustausch zwischen zwei Java-Programmen Allgemeine Java-Themen 5
A Differenz zwischen zwei Uhrzeiten Allgemeine Java-Themen 7
G Linked List zwischen zwei Threds übergeben Allgemeine Java-Themen 11
T Anzahl Tage zwischen zwei Daten - Stunde fehlt? Allgemeine Java-Themen 2
2 Tage zwischen zwei Datumsdaten zählen Allgemeine Java-Themen 2
G Tage zwischen zwei Datumsdaten zählen Allgemeine Java-Themen 3
C kürzester weg zwischen zwei Punkten, Koordinaten finden Allgemeine Java-Themen 15
L Anzahl Tage zwischen zwei Kalenderdaten Allgemeine Java-Themen 5
Z Zwei Listener zwischen zwei Klassen Allgemeine Java-Themen 4
D Schnittstelle zwischen zwei Klassen? Allgemeine Java-Themen 2
C Communication zwischen zwei Projekte - static objects Allgemeine Java-Themen 4
B Sent and Receive Funktionen zwischen Objekten ermöglichen? Allgemeine Java-Themen 8
Master3000 Dateien zwischen verschiedenen Netzwerken senden Allgemeine Java-Themen 17
CptK Backpropagation parallelisieren: Kommunikation zwischen den Threads Allgemeine Java-Themen 7
L Unterschied zwischen List und LinkedList implementierung? Allgemeine Java-Themen 15
B Schnittstelle zwischen MySQL und Apache Allgemeine Java-Themen 8
TonioTec Api für Datenaustausch zwischen Client und Server Allgemeine Java-Themen 0
Kirby.exe Schauen ob ein Kante zwischen Knoten existiert Allgemeine Java-Themen 4
L Schlüsselworte Wie kann ich am Besten ein LocalDate zwischen Anfangs und EndDate checken Allgemeine Java-Themen 10
N Kollision zwischen ImageIcon und Rechteck Allgemeine Java-Themen 1
B Zufällig zwischen vorgegebenen Zahlen auswählen Allgemeine Java-Themen 6
J Millisekunde zwischen 2 Daten Allgemeine Java-Themen 6
F Unterschied zwischen NormalizedValue und Value Allgemeine Java-Themen 5
J Abhängigkeit zwischen Rechenzeit und Speicherbedarf in einen Algorithmus Allgemeine Java-Themen 7
T Strings über Bluetooth zwischen PC,µc oder Samrtphone senden und empfangen Allgemeine Java-Themen 0
V Input/Output Austausch von Bytes zwischen C# und Java Allgemeine Java-Themen 3
L Kommunikation zwischen C# und Java? Allgemeine Java-Themen 5
A Best Practice Unterschied zwischen einer sauberen Dependency Injection und einer statischen Klasse Allgemeine Java-Themen 5
R jTable, nur Werte zwischen 2 Double values ausgeben Allgemeine Java-Themen 3
J Wie erschaffe ich einen sicheren Datenaustausch zwischen Thread und Nicht-Threads Allgemeine Java-Themen 8
M Unterschied zwischen Win 7/2008R2 und Win8.1/2012R2? Allgemeine Java-Themen 8
N Zeitabstand zwischen 2 Daten(Mehrzahl von Datum) Allgemeine Java-Themen 3
O Socket-Unterschiede zwischen Windows und Ubuntu Allgemeine Java-Themen 2
Z Vergleich zwischen int und Object Allgemeine Java-Themen 1
H Gibt es einen großen Unterschied zwischen Java 6 und Java 7? Allgemeine Java-Themen 3
S Eclipse Abhängigkeiten zwischen den Projekten in Eclipse Allgemeine Java-Themen 2
G nervendes Problem mit unterschieden zwischen Javax64 und x86 | je nach Programmbedarf beides nötig Allgemeine Java-Themen 2
S Threads Kommunikation zwischen SocketThread und WorkerThread Allgemeine Java-Themen 11
J Java-Implementierung diverser Beziehungen zwischen Klassen bzw. Objekten Allgemeine Java-Themen 2
B Unteschiede zwischen Kantenoperatoren Allgemeine Java-Themen 3
A Kommunikation zwischen 2 Jar-dateien Allgemeine Java-Themen 16
X Datentypen Prozentualer Abgleich zwischen 2 Strings (Pattern?) Allgemeine Java-Themen 3
Z zeit zwischen maus drücken und loslassen Allgemeine Java-Themen 7
C Komisches Verhalten zwischen Set und List bei contains Allgemeine Java-Themen 6
N Gridbaglayout - Abstände zwischen Komponenten einstellen Allgemeine Java-Themen 2
D Exakte Unterschied zwischen diesen Elementen? Allgemeine Java-Themen 5
C Swing Daten zwischen JTable teilen Allgemeine Java-Themen 6
N Unterschied zwischen "Java" und "Java mit Eclipse" Allgemeine Java-Themen 17
X Bild im Memory zwischen speichern Allgemeine Java-Themen 11
T Zugriff zwischen Klassen für repaint Allgemeine Java-Themen 7
S Assoziation zwischen 2 klassen Allgemeine Java-Themen 14
V Threads & Pipes Datenaustausch zwischen Threads Allgemeine Java-Themen 2
G Hauptthread anhalten / Unterschied zwischen Main-Thread und dialogelement-Thread Allgemeine Java-Themen 2
C Strings zwischen 2 Zeichen auslesen Allgemeine Java-Themen 7
Lufti Unterschied zwischen Djava.library.path und Class-Path im Manifest? Allgemeine Java-Themen 2
E kommunikation zwischen Fenstern Allgemeine Java-Themen 3
B Unterschied zwischen Klasse und Objekt? Allgemeine Java-Themen 8
S Datenformat zum Austausch zwischen Java und Python? Allgemeine Java-Themen 3
G Interface zwischen 2 Programmierern Allgemeine Java-Themen 10
B Gibt es einen Unterschied zwischen Java 1.2 und Java 2? Allgemeine Java-Themen 7
J Unterschied zwischen "Debug" und "Run" Allgemeine Java-Themen 16
A java.io-Änderungen zwischen java 1.4 und 1.6 Allgemeine Java-Themen 18
G Zwischen Datei und Verzeichnis unterscheiden. Allgemeine Java-Themen 11
J Unterschiede zwischen normaler und Debug Ausfuehrung? Allgemeine Java-Themen 2
J Suche regex-Pattern fuer Liste von Zahlen zwischen 0-100 Allgemeine Java-Themen 6
A Kommunikation zwischen C++ und Java-Programm Allgemeine Java-Themen 4
C JTable, Abstand zwischen Zellen Allgemeine Java-Themen 2
G Unterschiede zwischen Java 5 und 6 Allgemeine Java-Themen 5
P Unterschied zwischen Funktion und Methoden Allgemeine Java-Themen 3
T Möglichkeiten der Kommunikatin zwischen Plugins in Ecl. RCP Allgemeine Java-Themen 3
O Unterschied zwischen ThreadPoolExecutor und Executor Service Allgemeine Java-Themen 7
T JDBC: Unterschiede in Interfaces zwischen 2 Java-Versionen. Allgemeine Java-Themen 6
O Unterschied zwischen Semaphoren/Lock und ExecutorService Allgemeine Java-Themen 3
G Entscheidungsproblem für mein Vorhaben, zwischen Java und C# Allgemeine Java-Themen 35
MQue Daten-Austausch zwischen Klassen verschiedener Pakete Allgemeine Java-Themen 5
MQue Datenaustausch zwischen 2 Klassen Allgemeine Java-Themen 10
MQue zwischen Class zum speichern von Werten Allgemeine Java-Themen 4
I Unterschied zwischen Applet und JApplet Allgemeine Java-Themen 2
O Regex Texte zwischen html code Allgemeine Java-Themen 4
J Interaktion zwischen Klassen Allgemeine Java-Themen 4
W Beziehungen zwischen Usern ermitteln Allgemeine Java-Themen 2
G Daten aus einer For Schleife zwischen speichern Allgemeine Java-Themen 4
M Wie mit Dateipfaden zwischen Linux und WIndows hantieren? Allgemeine Java-Themen 2
M Kommunikation zwischen 2 Programmen Allgemeine Java-Themen 7
G Kommunikation zwischen Threads und Gui Allgemeine Java-Themen 2
S Unterschiede zwischen SWINGS; Struts und AWT Allgemeine Java-Themen 4
P kommunikation zwischen dialog und threads Allgemeine Java-Themen 4
R Der Unterschied zwischen 2.1 und 2.10 Allgemeine Java-Themen 2
Q Typecast zwischen Klassen mit implementierter Schnittstelle Allgemeine Java-Themen 4
P Was ist der Unterschied zwischen JSP und Servlet ? Allgemeine Java-Themen 4
S zufallszahl zwischen -1 und 1 Allgemeine Java-Themen 9
T Unterschiede beim KeyListener zwischen NT und XP Allgemeine Java-Themen 6

Ähnliche Java Themen

Neue Themen


Oben