Klassen Spaghetti Code Vermeidung

friednoodles

Aktives Mitglied
Hallo, ich wollte euch mal um Rat bitten wie ich meinen Code klüger gliedern kann.
Ich habe vor 3 Monaten das Programmieren angefangen und habe es geschafft ein Programm mit kleinen nützlichen Funktionalitäten zu schreiben. Nur ist mein Problem das Programm ist inzwischen 400 Zeilen lang und niemand außer mir Blickt so wirklich durch den Code durch.

Hat jemand allgemeine Tipps für mich wie ich anfangen könnte den Code klüger aufzuteilen?
Mein Code hat etliche Methoden die alle kreuz und quer auf einander zugreifen und ich finde es unglaublich schwer einen Anfangspunkt zum Aufräumen zu finden.

Liebe Grüße,

Friednoodles
 

Robat

Top Contributor
Hat jemand allgemeine Tipps für mich wie ich anfangen könnte den Code klüger aufzuteilen?
Erst Nachdenken und dann anfangen zu Programmieren.
Wenn du ein neues Projekt anfängst überleg dir, welche Funktionalitäten dein Programm hat und wie diese zusammenspielen. Überleg dir wie du die Beziehungen brauchst und wie du das ganze sinnvoll in Klassen / Methoden aufteilst.

Wichtig: Nicht alles in eine eigene Klasse .. SRP
 

Javinner

Top Contributor
@friednoodles
Poste doch dein Programm hier, benutze bitte dafür Code-Tags, und beschreibe kurz, was das Programm macht usw. Dann wird dieser Thread garantiert! mehrere Seiten Lang, die den Weg aufzeichnen, wie Du DEIN Programm unter Anleitung und Vorschlägen optimierst ;) Ist ein schmerzhafter und lehrreicher Prozess!
 

friednoodles

Aktives Mitglied
Ich glaube meinen ganzen Code kann ich leider nicht posten. Aber ich habe vier Methoden auf die ich etwas näher eingehen kann. Diese würde ich Beispielsweise gerne aus meiner Klasse in der bisher ALLES passiert rausnehmen und in eine andere Klasse verschieben.
Kurzgesagt wandelt mein Programm ein Datum im Format yyyy-MM-dd HH:mm:ss in eine Epoch Timestamp um und umgekehrt geht das auch. Die Eingabe findet in einem TextField statt und wird auf eine TextArea ausgegeben.

Diese Methode gibt mir das Ergebnis der Umwandlung in der TextArea aus.
Java:
private void showResult() {
        textArea.setText(whichPattern());
    }
Diese Methode überprüft welches Pattern zu dem TextField Input passt
Java:
    private String whichPattern() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String textFieldInput = textField.getText();
        Date parsInToDate = new Date();
        long epochMillis;

        if (textFieldInput.isEmpty()) {
            textArea.setText("You can't convert from nothing");
        } else if (Pattern.matches(
                "^\\d\\d\\d\\d-(0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01]) (00?[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$",
                textFieldInput)) {
            epochMillis = dateToEpochTime(sdf, textFieldInput, parsInToDate);
            textArea.setText(epochMillis + "");
        } else if (Pattern.matches("^[0-9]*$", textFieldInput)) {
            Calendar calendar = epochTimeToDate();
            textArea.setText(sdf.format(calendar.getTime()));
        } else {
            textArea.setText(textFieldInput + " is not a valid entry");
        }
        String textAreaOutput = textArea.getText();
        return textAreaOutput;
    }
Die hier führt eine Umwandlung durch:
Java:
    private long dateToEpochTime(SimpleDateFormat sdf, String textFieldInput, Date parsInToDate) {
        long epochMillis;
        try {
            parsInToDate = sdf.parse(textFieldInput);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        epochMillis = parsInToDate.getTime();
        return epochMillis;
    }
Und diese die Andere:
Java:
    private Calendar epochTimeToDate() {
        long long1 = Long.valueOf(textField.getText()).longValue();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(long1);
        return calendar;
    }

Diese vier Methoden sind neben ALLEN anderen die mein Programm hat in meiner einzigen Klasse "Konverter"
Am Thema refactoring hänge ich schon ziemlich lange, habe viele Beispiele gesehen und weiß aber einfach nicht wie ich es auf meinen speziellen Fall anwenden kann. Für Hilfe wäre ich sehr dankbar.
 

VfL_Freak

Top Contributor
Moin,
ich würde evtl. nochmal ein paar Kleinigkeiten an der Namensgebung ändern!

"whichPattern" ist ein recht seltsamer Name. Etwas Sprechenderes wäre schön!
Und was genau ist "Epoch" ??

VG Klaus
 

friednoodles

Aktives Mitglied
Moin,
ich würde evtl. nochmal ein paar Kleinigkeiten an der Namensgebung ändern!

"whichPattern" ist ein recht seltsamer Name. Etwas Sprechenderes wäre schön!
Und was genau ist "Epoch" ??

VG Klaus
Danke dir, darum sollte ich mich auch kümmern ja.
Was genau "Epoch" ist fragst du? Hab ich das irgendwo nicht richtig benannt oder möchtest du eine Definition?
Die Epoch time sind doch einfach Millisekunden seit dem 01.01.1970 00:01:00, also heute wäre das beispielsweise eine 13 stellige Zahl.
 

Robat

Top Contributor
Generell solltest du View, Model und Logik von einander trennen. Wenn du also selber sagst, dass bspw. showResult() [View] und dateToEpochTime(SimpleDateFormat, String, Date) [Logik] in der selben Klasse stehen, läuft etwas falsch. Schau dir dazu am Besten mal das ModelViewController-Pattern an.

Außerdem würde ich nicht mehr auf die Calendar API setzen. Seit Java 8 gibt es eine neue Date & Time API mit der sich einige Dinge leichter umsetzen lassen. Schau dir diese vielleicht mal an.

Deine Methode whichPattern() macht mEn gerade zu viel auf einmal. (SRP) Sie holt sich den Text von aus der GUI, verarbeitet die Daten und gibt eine Nachricht auf der GUI aus. Außerdem würde diese Methode gerade nur für Swing funktionieren, weil sie vom JTextArea abhängig ist. Übergib' der Methode doch den String und gib den Text, den du auf der TextArea anzeigen lassen willst, zurück.

ist ein etwas seltsamer, wenig aussagekräftiger Begriff
@VfL_Freak Epoch ist doch aber ein gängiger Begriff sogar in der Java Date-Time-API. Siehe zB. LocalDate#toEpochDay() :p
 

mrBrown

Super-Moderator
Mitarbeiter
genau, ist ein etwas seltsamer, wenig aussagekräftiger Begriff und fiel in Deinem Code 'etwas vom Himmel' ;)
epochMillis/epochTime ist doch einfach nur ein Domänenspezifischer Begriff, was soll man denn stattdessen verwenden? o_O

Diese Methode überprüft welches Pattern zu dem TextField Input passt
Absehen von dem schon angesprochenen Namen macht die Methode zwei Dinge: Daten aus dem Textfeld holen und mit diesen arbeiten. Leichter machst du es, wenn du beide Dinge trennst. Das Verarbeiten der Daten ist dann wiederverwendbar und testbar.
 

friednoodles

Aktives Mitglied
@Robat
Ich habe versucht deinen Ratschlägen zu folgen und habe eine neue Klasse "KonverterTools" erstellt.
Java:
 KonverterTools tools = new KonverterTools();
Meine View, die noch in der alten Klasse ist:
Java:
    private void showResult() {
        textArea.setText(tools.whichPattern(this.textField.getText()));
    }
Und die Folgenden drei Methoden sind jetzt in der neuen Klasse:
Mir fällt für meine ehemalige whichPattern() Methode einfach kein guter Name ein :/
Habe hier als Parameter einfach einen String eingeführt, damit kann ich mir die textArea in dieser Methode ja sparen, oder? Funktionieren tut es zumindest.
Java:
    public String PatternQuery(String toCheck) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parsInToDate = new Date();
        long epochMillis;
       
        if (toCheck.isEmpty()) {
            return "You can't convert from nothing";
        } else if (Pattern.matches(
                "^\\d\\d\\d\\d-(0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01]) (00?[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$",
                toCheck)) {
            epochMillis = dateToEpochTime(sdf, toCheck, parsInToDate);
            return epochMillis + "";
        } else if (Pattern.matches("^[0-9]*$", toCheck)) {
            Calendar calendar = epochTimeToDate(Long.parseLong(toCheck));
            return sdf.format(calendar.getTime());
        } 
        return toCheck + " is not a valid entry";
    }
In dieser Methode muss ich soweit nichts ändern denke ich.
Java:
    private long dateToEpochTime(SimpleDateFormat sdf, String textFieldInput, Date parsInToDate) {
        long epochMillis;
        try {
            parsInToDate = sdf.parse(textFieldInput);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        epochMillis = parsInToDate.getTime();
        return epochMillis;
    }
Und hier habe ich einfach wieder einen Parameter hinzugefügt und konnte eine Zeile löschen.
Java:
    private Calendar epochTimeToDate(Long timestamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp);
        return calendar;
    }

Funktionieren tut alles so wie bisher. Nur ist die Frage ob das konform genug ist?
 

Robat

Top Contributor
Mir fällt für meine ehemalige whichPattern() Methode einfach kein guter Name ein :/
Versuch doch mal in Worten zu beschreiben, was die Methode macht und dann überlegst du dir einen kurzen, aussagekräftigen, (englischen) Namen für die Methode.

Warum bekommt dateToEpochTime denn das SimpleDateFormat übergeben? Es ist doch immer das selbe Pattern, was du zum parsen brauchst, oder?
Ansonsten noch ein Hinweis: Variablen immer so spät wie nötig deklarieren und so früh wie möglich initialisieren. Bedeutet für dein konkretes Beispiel:
Java:
public String patternQuery(String toCheck) {
    ...
    long epochMillis;
    if(...) {
      
    } else if( ... ) {
        epochMillis = ...
        ...
    } else if( ...) { ... }
    return ...
}
Du verwendest epochMillis nur in dem zweiten else-if, deklarierst die Variable aber schon ganz am Anfang der Methode.
Das mag bei so einer Methode vielleicht nicht stören aber sollte diese doch mal etwas länger werden, mit etwas mehr Variablen, verliert man schnell den Überblick. Zieh die Deklaration lieber mit in die if-Anweisung rein
 

Javinner

Top Contributor

mihe7

Top Contributor
Ich habe versucht deinen Ratschlägen zu folgen und habe eine neue Klasse "KonverterTools" erstellt.
Klassen, die Tools, Utils oder ähnliches im Namen haben, sind Indiz für Designfehler oder für die Faulheit des Entwicklers oder beides :)

Mir fällt für meine ehemalige whichPattern() Methode einfach kein guter Name ein
Das ist tatsächlich problematisch: gute Namen finden.

Mal so als Idee:
Code:
class DateMillis {
    private final Date date;
    private static final SimpleDateFormat sdf = 
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private boolean millis;

    private DateMillis(Date date, boolean millis) {
        this.date = date;
        this.millis = millis;
    }

    public static DateMillis parse(String text) {
        if (Pattern.matches(DATE_PATTERN, text)) {
            return new DateMillis(sdf.parse(text), false);
        } else if (Pattern.matches(MILLIS_PATTERN, text)) {
            return new DateMillis(new Date(Long.valueOf(text)), true);
        } else {
            throw new IllegalArgumentException();
        }
    }

    public DateMillis inverse() {
        this.millis = !millis;
        return this;
    }

    public String toString() {
        return millis ? String.valueOf(date.getTime()) : sdf.format(date);
    }
}

Benutzung:
Code:
textField.setText(DateMillis.parse(textField.getText()).inverse().toString());

Achtung: der Spaß ist ungetestet.
 

friednoodles

Aktives Mitglied
Warum bekommt dateToEpochTime denn das SimpleDateFormat übergeben? Es ist doch immer das selbe Pattern, was du zum parsen brauchst, oder?
Ja das Pattern ist immer das selbe. Wenn ich sdf aber nicht übergebe kommen lauter Fehlermeldungen die damit enden, dass Eclipse von mir möchte SimpleDateFormat in static zu ändern. Lass es deswegen einfach drin.

Ansonsten noch ein Hinweis: Variablen immer so spät wie nötig deklarieren und so früh wie möglich initialisieren. Bedeutet für dein konkretes Beispiel:
Java:
public String patternQuery(String toCheck) {
    ...
    long epochMillis;
    if(...) {
   
    } else if( ... ) {
        epochMillis = ...
        ...
    } else if( ...) { ... }
    return ...
}
Du verwendest epochMillis nur in dem zweiten else-if, deklarierst die Variable aber schon ganz am Anfang der Methode.
Danke für den Tipp, habe meinen Code dementsprechend angepasst.


Du erstellst bei jedem Aufruf von PatternQuery, was nach den Regeln hätte patternQuery heißen sollen, immer ein neues SimpleDataFormat. Dieses Format übergibst du dann an eine weitere Methode, so dass ich hier es als eine finale Klassenvariable erstellt hätte.
Also einfach aus
Java:
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
das hier machen?
Java:
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 

friednoodles

Aktives Mitglied
Klassen, die Tools, Utils oder ähnliches im Namen haben, sind Indiz für Designfehler oder für die Faulheit des Entwicklers oder beides :)
Wie würdest du das ab ändern? Einfach einen passenderen Namen auswählen oder noch mehr aus dieser Klasse rausziehen?

Mal so als Idee:
Code:
class DateMillis {
    private final Date date;
    private static final SimpleDateFormat sdf =
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private boolean millis;

    private DateMillis(Date date, boolean millis) {
        this.date = date;
        this.millis = millis;
    }

    public static DateMillis parse(String text) {
        if (Pattern.matches(DATE_PATTERN, text)) {
            return new DateMillis(sdf.parse(text), false);
        } else if (Pattern.matches(MILLIS_PATTERN, text)) {
            return new DateMillis(new Date(Long.valueOf(text)), true);
        } else {
            throw new IllegalArgumentException();
        }
    }

    public DateMillis inverse() {
        this.millis = !millis;
        return this;
    }

    public String toString() {
        return millis ? String.valueOf(date.getTime()) : sdf.format(date);
    }
}

Benutzung:
Code:
textField.setText(DateMillis.parse(textField.getText()).inverse().toString());

Achtung: der Spaß ist ungetestet.
Mit ein paar Anpassungen funktioniert das tatsächlich, danke für den Vorschlag :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Unsicher, ob das Code richtig ist Allgemeine Java-Themen 4
MarvinsDepression Unbekanntes Zeichen in fremden Code wirft Fragen auf Allgemeine Java-Themen 4
schemil053 Methoden Code-Verbesserung Allgemeine Java-Themen 2
D Webarchive (war): Code verschleiern Allgemeine Java-Themen 7
D Compiler-Fehler child process exited with code 1 Allgemeine Java-Themen 1
Queenman Interface Mein Microsoft Visual Studio Code zeigt komische Dinge & Menüs an Allgemeine Java-Themen 9
A Clean Code: Variable vs. Methode Allgemeine Java-Themen 8
berserkerdq2 Versteht jemand, was diese beiden Zahlen bei dem IJVM Code zu bedeuten haben? Allgemeine Java-Themen 10
OnDemand Releaseversion Tag in Code Allgemeine Java-Themen 5
ERlK JDA Code funktioniert nicht? Allgemeine Java-Themen 4
F Code auslagern Allgemeine Java-Themen 5
D VBA Code mit Java ausführen möglich? Allgemeine Java-Themen 10
N JAVA-Code mit Grafikfenster zeichnet in Windows, aber nicht Mac. Allgemeine Java-Themen 4
JordenJost Unverständlicher Java code? Allgemeine Java-Themen 21
V Hilfe mit Java Code Allgemeine Java-Themen 4
S Processing Java Code verstehen Allgemeine Java-Themen 4
A code wird nicht ausgeführt Allgemeine Java-Themen 3
B Bitte um Code Erklärung Allgemeine Java-Themen 5
N nicht einsehbarer Fehler im code, kann nicht mehr übersetzten Allgemeine Java-Themen 51
N Regulären Ausdruck in normalen Java-Code umwandeln Allgemeine Java-Themen 12
OnDemand Clean Code oder Allgemeine Java-Themen 5
Noahscript Aus einem byte Array Steuerungszeichen und Code bekommen und ersetzen Allgemeine Java-Themen 3
J Simple Date Format Alternativen bitte um Code Allgemeine Java-Themen 14
AGW in Java-Code plötzlich ein paar Wörter in Rot Allgemeine Java-Themen 2
L Best Practice Auslagerung von Code = Performance Optimierung? Allgemeine Java-Themen 4
H Precompilierten code ansehen Allgemeine Java-Themen 3
R Wo müsste ich im Code eine Änderung vornehmen? Allgemeine Java-Themen 6
L Ausgabe von in Echtzeit ausgeführten Code Allgemeine Java-Themen 9
Drachenbauer Wie kann ich die menge an code reduzieren? Allgemeine Java-Themen 28
Thallius Warum ist dieser Code OS abhängig? Allgemeine Java-Themen 10
S Code Erklärung Allgemeine Java-Themen 21
B Pausem im Code Allgemeine Java-Themen 2
T Java-Quiz Code Fehler Allgemeine Java-Themen 10
L Eclipse Java Code ausführen Allgemeine Java-Themen 18
F Java Code ausführen direkt nach Anmelden in Windows Allgemeine Java-Themen 2
F Code in Klassen bringen Allgemeine Java-Themen 4
S Gibt es eigentlich Java Source Code Interpreter..? Allgemeine Java-Themen 13
J JUnit - Auslassen von Code Allgemeine Java-Themen 25
C code oder Bibliotheken für 2-Center Problem Allgemeine Java-Themen 4
J Code Page characters darstellen Allgemeine Java-Themen 12
J wie sollte man sinnvoll seinen Code aufteilen Allgemeine Java-Themen 6
I Python Code in Java Code Allgemeine Java-Themen 9
M Java (GUI) Code verdoppeln oder anzeige mehrmals anzeigen? Allgemeine Java-Themen 8
N Wie öffne ich einen runtergeladadenen Code in IntelliJ Allgemeine Java-Themen 3
R Fehler im Code Allgemeine Java-Themen 1
R Fehler im Code Allgemeine Java-Themen 3
O Standard library nativer C code Allgemeine Java-Themen 1
R Wo ist mein Fehler in diesem Code Allgemeine Java-Themen 7
S Java Editor Bekomme bei der Code-Vervollständigung die Zeichen ​ Allgemeine Java-Themen 3
N Morse Code decoder Allgemeine Java-Themen 9
O Erste Schritte Benzinverbrauch Code Hilfe Allgemeine Java-Themen 3
S Eclipse exit code 805306369 Allgemeine Java-Themen 1
Pataraca Vererbung Code einbinden Allgemeine Java-Themen 3
Developer_X Website HTML Code von HTTPS URL laden Allgemeine Java-Themen 0
S Wie kann ich eine kleine Stelle in meinem Code mit multiplen Threads abarbeiten..? Allgemeine Java-Themen 20
S Code 'innerhalb' des synchronen Bereichs einer BlockingQueue ausfuehren..? Allgemeine Java-Themen 7
F Verständlichkeitsproblem bei Java Code?! Allgemeine Java-Themen 2
G Eclipse Eclipse: Unreachable code Allgemeine Java-Themen 16
P Java Android Code in IOS compilieren? Allgemeine Java-Themen 9
C Code vereinfachen Allgemeine Java-Themen 2
T Hilfe bei Code Allgemeine Java-Themen 3
R Java-Code für folgene Aufgabe? Allgemeine Java-Themen 8
Prafy Best Practice Code Refaktorisierung Allgemeine Java-Themen 7
WetWer Was bedeutet/macht ein Exit-Code Allgemeine Java-Themen 1
D Code für bereitgestellte Methoden Allgemeine Java-Themen 1
perlenfischer1984 HTML Code decodieren Allgemeine Java-Themen 2
C ASCII-Code in Java Allgemeine Java-Themen 1
J Java-Code in DLL packen Allgemeine Java-Themen 5
J LWJGL 3 Error Code 1282 Allgemeine Java-Themen 4
0 Code startet nicht (Keine Warnung/Fehlermeldung) Allgemeine Java-Themen 4
A Frage zu meinem Code Allgemeine Java-Themen 2
B Code generierung Velocity Templates Telosys Allgemeine Java-Themen 1
E Fehlermeldung vor dem Programm code Allgemeine Java-Themen 1
B JAVA - mehrere Clienten gleichzeitig starten. Nicht bei Code! Allgemeine Java-Themen 3
Fischkralle Ausführen von fremden Code Allgemeine Java-Themen 14
wolfgang63 Code snipped Software Allgemeine Java-Themen 1
L Eclipse Editieren des Code templates für Override methods Allgemeine Java-Themen 2
J Java code "plugin" fähig machen Allgemeine Java-Themen 4
alderwaran .jar Code Signing, User-Keystore und Fragen dazu Allgemeine Java-Themen 0
Thallius Wie verstecke ich meinen private Key am besten im Code? Allgemeine Java-Themen 10
A Thread: Code paralell ausführen in mehreren Instanzen Allgemeine Java-Themen 1
B NullPointerException - Aber kein Fehler im Code Allgemeine Java-Themen 4
N HTTP response code: 403 Allgemeine Java-Themen 3
D Code bitte mit 19 stelligen Zahlen kompatibel machen Allgemeine Java-Themen 5
D Java Compiler code referencen Allgemeine Java-Themen 0
B Fehler im Java-Code Allgemeine Java-Themen 4
A PHP-Code zu Java-Code Allgemeine Java-Themen 5
M Code läuft unter windows aber nicht unter Linux Allgemeine Java-Themen 6
X Was macht folgender Code!? Allgemeine Java-Themen 6
K Code zu einem Projekt entschluesseln Allgemeine Java-Themen 15
H Java Leistungssteigerung durch Code Anpassung Allgemeine Java-Themen 5
Fab1 Best Practice Vorgehensweise bestehenden Code/Programm verschönern Allgemeine Java-Themen 4
M Code optimieren Allgemeine Java-Themen 7
A jEditorPane Html Datei öffnen (code) Allgemeine Java-Themen 3
S EAN-Code Tabelle für CD's Allgemeine Java-Themen 2
T Code durch eigenes Frame pausieren (ähnlich JDialog) Allgemeine Java-Themen 4
J Erzeugung von Java-Code Allgemeine Java-Themen 2
A Source code analyze Allgemeine Java-Themen 8
N VB Code in Java verwenden Allgemeine Java-Themen 5
P Aktuellen HTML Code auslesen (von JS manipuliert) Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben