---
lang: de
format:
    pdf:
        toc: true
        number-sections: true
        colorlinks: true
crossref:
    custom:
      - kind: float
        reference-prefix: UML-Diagramm
        key: uml
        latex-env: uml
        latex-list-of-description: UML-Diagramme
---

# Code Smell 1: Long Method

## Beschreibung des Problems

Das **Long Method** Anti-Pattern tritt auf, wenn eine einzelne Methode zu viele Zeilen Code enthält und multiple Verantwortlichkeiten übernimmt. Eine solche Methode verstößt gegen das **Single Responsibility Principle (SRP)** und führt zu verschiedenen Problemen:

- **Schwere Verständlichkeit**: Entwickler müssen viel Zeit aufwenden, um die gesamte Methode zu durchdringen
- **Reduzierte Testbarkeit**: Verschiedene Logikbereiche können nicht isoliert getestet werden
- **Mangelnde Wiederverwendbarkeit**: Teilfunktionalitäten sind nicht separat nutzbar
- **Erhöhte Fehleranfälligkeit**: Bugs sind schwerer zu lokalisieren und zu beheben

## Praktisches Beispiel

Die folgende Methode `stopRunFromBackend()` zeigt ein typisches Long Method Problem:

### Vorher (Problematischer Code)

```java
public static void stopRunFromBackend(String message){
    // Zustandsänderungen
    isAutoRunActive = false;
    if (isSleeping)
        wakeUpFromSleep();
    else
        DataRegister.resetPC();

    // UI-Erstellung und -Konfiguration
    Stage stoppedStage = new Stage();
    stoppedStage.setTitle("Programm unterbrochen!");
    VBox vbox = new VBox();
    vbox.setAlignment(javafx.geometry.Pos.CENTER);
    Label grundlabel = new Label("Grund: " + message);
    grundlabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;");
    Label ueberlabel = new Label("Programm unterbrochen!");
    vbox.getChildren().add(ueberlabel);
    vbox.getChildren().add(grundlabel);
    VBox.setMargin(grundlabel, new javafx.geometry.Insets(10, 10, 10, 10));
    Scene scene = new Scene(vbox, 300, 90);
    stoppedStage.setAlwaysOnTop(true);
    stoppedStage.setScene(scene);
    stoppedStage.show();
}
```

### Identifizierte Probleme

- **Vermischte Verantwortlichkeiten**: Die Methode kombiniert Geschäftslogik (Zustandsänderungen) mit UI-Code
- **Schwere Testbarkeit**: UI-Code kann nicht isoliert von der Geschäftslogik getestet werden
- **Code-Duplikation**: Wird die Dialog-Funktionalität anderswo benötigt, muss der gesamte UI-Code kopiert werden

## Lösung: Extract Method Refactoring

Die **Extract Method** Technik löst das Problem durch Aufspaltung der langen Methode in kleinere, fokussierte Methoden:

### Nachher (Refactorierter Code)

```java
public static void stopRunFromBackend(String message){
    handleExecutionStop();
    showInterruptionDialog(message);
}

private static void handleExecutionStop(){
    isAutoRunActive = false;
    if (isSleeping)
        wakeUpFromSleep();
    else
        DataRegister.resetPC();
}

private static void showInterruptionDialog(String message){
    Stage stoppedStage = new Stage();
    stoppedStage.setTitle("Programm unterbrochen!");

    VBox vbox = new VBox();
    vbox.setAlignment(javafx.geometry.Pos.CENTER);

    Label ueberlabel = new Label("Programm unterbrochen!");
    Label grundlabel = new Label("Grund: " + message);
    grundlabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;");

    vbox.getChildren().addAll(ueberlabel, grundlabel);
    VBox.setMargin(grundlabel, new javafx.geometry.Insets(10, 10, 10, 10));

    Scene scene = new Scene(vbox, 300, 90);
    stoppedStage.setAlwaysOnTop(true);
    stoppedStage.setScene(scene);
    stoppedStage.show();
}
```

## Vorteile der Lösung

- **Klare Trennung der Verantwortlichkeiten**: Geschäftslogik und UI-Code sind getrennt
- **Verbesserte Lesbarkeit**: Jede Methode hat einen klaren, fokussierten Zweck
- **Erhöhte Wiederverwendbarkeit**: `showInterruptionDialog()` kann in anderen Kontexten genutzt werden
- **Bessere Testbarkeit**: Geschäftslogik und UI können separat getestet werden


# Code Smell 2: Large Class

## Beschreibung des Problems

Eine **Large Class** entsteht, wenn eine Klasse zu viele Verantwortlichkeiten übernimmt und dadurch überladen wird. Typische Kennzeichen sind:

- **Hohe Anzahl an Instanzvariablen**: Die Klasse verwaltet zu viele verschiedene Datentypen
- **Viele Methoden**: Unterschiedliche Funktionsbereiche werden in einer Klasse gemischt
- **Multiple Domänenaspekte**: Logik, Darstellung, Benutzerinteraktion und Statusverwaltung in einer Klasse

## Praktisches Beispiel

Die Klasse `Controller_Frontend` zeigt typische Large Class Probleme:

### Identifizierte Probleme

```java
public class Controller_Frontend {
    // GUI-Elemente
    @FXML private Button startButton;
    @FXML private Button pauseButton;
    @FXML private Label statusLabel;

    // Zustandsverwaltung (gehört nicht hierher!)
    private static boolean isAutoRunActive = false;
    private static boolean isSleeping = false;
    private static double executionTimeMultiplier = 1.0;

    // GUI-Steuerung
    public void handleStart() { /* ... */ }
    public void handlePause() { /* ... */ }

    // Zustandslogik (gehört nicht hierher!)
    public void sleep() { isSleeping = true; }
    public void wakeUpFromSleep() { isSleeping = false; }

    // ... viele weitere Methoden
}
```

### Auswirkungen

- **Schwere Wartbarkeit**: Änderungen in einem Bereich können unbeabsichtigte Nebeneffekte verursachen
- **Reduzierte Testbarkeit**: Verschiedene Aspekte können nicht isoliert getestet werden
- **Unübersichtlichkeit**: Die Klasse wird schnell unhandlich und schwer verständlich
- **Violierung des Single Responsibility Principle**: Eine Klasse sollte nur einen Grund zur Änderung haben

## Lösung: Extract Class Refactoring

Die Lösung besteht in der Auslagerung der Zustandsverwaltung in eine separate, spezialisierte Klasse:

### Neue ExecutionState Klasse

```java
/**
 * Zentrale Verwaltung aller Ausführungszustände.
 * Diese Klasse kapselt alle zustandsbezogenen Operationen
 * und bietet eine saubere API für den Zugriff darauf.
 */
public class ExecutionState {
    private static boolean isAutoRunActive = false;
    private static boolean isSleeping = false;
    private static double executionTimeMultiplier = 1.0;

    // AutoRun-Zustand
    public static boolean isAutoRunActive() {
        return isAutoRunActive;
    }

    public static void setAutoRunActive(boolean active) {
        isAutoRunActive = active;
    }

    // Sleep-Zustand
    public static boolean isSleeping() {
        return isSleeping;
    }

    public static void sleep() {
        isSleeping = true;
    }

    public static void wakeUp() {
        isSleeping = false;
    }

    // Ausführungsgeschwindigkeit
    public static double getExecutionTimeMultiplier() {
        return executionTimeMultiplier;
    }

    public static void setExecutionTimeMultiplier(double multiplier) {
        if (multiplier > 0) {
            executionTimeMultiplier = multiplier;
        }
    }

    // Hilfsmethoden
    public static void reset() {
        isAutoRunActive = false;
        isSleeping = false;
        executionTimeMultiplier = 1.0;
    }
}
```

### Refactorierte Controller Klasse

```java
public class Controller_Frontend {
    // Nur noch GUI-Elemente
    @FXML private Button startButton;
    @FXML private Button pauseButton;
    @FXML private Label statusLabel;

    // Verwendung der ExecutionState Klasse
    public void stopRunFromBackend(String message) {
        ExecutionState.setAutoRunActive(false);

        if (ExecutionState.isSleeping()) {
            ExecutionState.wakeUp();
        } else {
            DataRegister.resetPC();
        }

        showInterruptionDialog(message);
    }

    // Weitere GUI-Methoden...
}
```

## Vorteile der Lösung

- **Klare Verantwortlichkeiten**: Controller fokussiert sich auf GUI, ExecutionState auf Zustandsverwaltung
- **Verbesserte Testbarkeit**: Zustandslogik kann isoliert getestet werden
- **Erhöhte Wiederverwendbarkeit**: ExecutionState kann in anderen Klassen genutzt werden
- **Bessere Wartbarkeit**: Änderungen an der Zustandslogik betreffen nur eine Klasse


# Code Smell 3: Shotgun Surgery

## Beschreibung des Problems

**Shotgun Surgery** tritt auf, wenn eine kleine fachliche Änderung Modifikationen an vielen verschiedenen Stellen im Code erfordert. Dieses Anti-Pattern entsteht durch:

- **Zu starke Verteilung**: Zusammengehörige Funktionalität ist über viele Klassen und Methoden verstreut
- **Mangelnde Kapselung**: Ähnliche Operationen sind nicht zentral gebündelt
- **Duplizierte Logik**: Gleiche oder ähnliche Code-Fragmente existieren an mehreren Stellen

## Praktisches Beispiel

Die Schlafmodus-Funktionalität war ursprünglich über mehrere Bereiche verteilt:

### Vor dem Refactoring (Problematische Verteilung)

```java
// In Controller_Frontend
private boolean isSleeping = false;

public void enterSleepMode() {
    isSleeping = true;
    // Logging hier
    System.out.println("Entering sleep mode");
}

// In ExecutionEngine
private boolean sleepState = false;

public void pauseExecution() {
    sleepState = true;
    // Ähnliches Logging dort
    System.out.println("Execution paused - sleep mode");
}

// In StatusManager
public void checkSleepStatus() {
    if (someCondition) {
        // Wieder ähnlicher Code
        setSleeping(true);
        System.out.println("Sleep mode activated");
    }
}
```

### Identifizierte Probleme

- **Mehrfache Implementierung**: Sleep-Logik existiert in verschiedenen Varianten
- **Inkonsistente Zustände**: Verschiedene Klassen können unterschiedliche Sleep-Zustände haben
- **Hoher Änderungsaufwand**: Neue Sleep-Features müssen an mehreren Stellen implementiert werden
- **Fehleranfälligkeit**: Beim Hinzufügen neuer Funktionen können leicht Stellen vergessen werden

## Lösung: Zentralisierung durch Extract Class

Die Lösung besteht in der Konsolidierung aller sleep-bezogenen Operationen in der `ExecutionState` Klasse:

### Zentralisierte Lösung

```java
public class ExecutionState {
    private static boolean isSleeping = false;
    private static final Logger logger = LoggerFactory.getLogger(ExecutionState.class);

    /**
     * Aktiviert den Schlafmodus mit einheitlichem Logging und Zustandsmanagement
     */
    public static void sleep() {
        if (!isSleeping) {
            isSleeping = true;
            logger.info("Sleep mode activated");
            notifyStateChange("SLEEP_ACTIVATED");
        }
    }

    /**
     * Deaktiviert den Schlafmodus
     */
    public static void wakeUp() {
        if (isSleeping) {
            isSleeping = false;
            logger.info("Waking up from sleep mode");
            notifyStateChange("SLEEP_DEACTIVATED");
        }
    }

    /**
     * Überprüft den aktuellen Schlafzustand
     */
    public static boolean isSleeping() {
        return isSleeping;
    }

    /**
     * Erweiterte Sleep-Funktionalität mit Timeout
     */
    public static void sleepWithTimeout(long milliseconds) {
        sleep();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                wakeUp();
            }
        }, milliseconds);
    }

    private static void notifyStateChange(String event) {
        // Zentrale Benachrichtigung für alle interessierten Komponenten
        EventBus.getInstance().publish(new StateChangeEvent(event));
    }
}
```

### Vereinfachte Nutzung in anderen Klassen

```java
// In Controller_Frontend
public void handleSleepButton() {
    ExecutionState.sleep();
    updateUI();
}

// In ExecutionEngine
public void pauseIfNeeded() {
    if (shouldPause()) {
        ExecutionState.sleep();
    }
}

// In StatusManager
public void checkAndActivateSleep() {
    if (criticalCondition()) {
        ExecutionState.sleepWithTimeout(5000); // 5 Sekunden Sleep
    }
}
```

## Vorteile der Lösung

- **Einheitliche Implementierung**: Alle sleep-bezogenen Operationen verwenden dieselbe Logik
- **Zentrale Wartung**: Änderungen müssen nur an einer Stelle vorgenommen werden
- **Konsistente Zustände**: Nur eine Quelle der Wahrheit für den Sleep-Zustand
- **Erweiterte Funktionalität**: Neue Features (wie Timeout) können zentral hinzugefügt werden
- **Bessere Nachverfolgbarkeit**: Einheitliches Logging und Event-System

# Anwendung von Programmierprinzipien im Projekt

## Einleitung
Im Rahmen der Refaktorisierung und Weiterentwicklung des Projekts wurde besonderer Fokus auf die Einhaltung zentraler Programmierprinzipien gelegt. Die folgenden Prinzipien wurden gezielt analysiert und angewendet:

## 1. SOLID-Prinzipien

### Single Responsibility Principle (SRP)
Die Methode `stopRunFromBackend()` wurde in zwei unabhängige Methoden aufgeteilt:

```java
public void stopRunFromBackend(String message) {
    ExecutionState.setAutoRunActive(false);
    handleSleepOrReset();
    showStopDialog(message);
}

private void handleSleepOrReset() {
    if (ExecutionState.isSleeping()) {
        ExecutionState.wakeUp();
    } else {
        dataRegister.resetPC();
    }
}

private static void showStopDialog(String message) {
    // GUI-Erzeugung...
}
```

### Open/Closed Principle (OCP)
Die Klasse `ExecutionState` kapselt erweiterbare Zustandslogik, ohne dass bestehende Methoden geändert werden müssen:

```java
public class ExecutionState {
    private static boolean isAutoRunActive;
    private static boolean isSleeping;

    public static boolean isSleeping() { return isSleeping; }
    public static void wakeUp() { isSleeping = false; }
    public static void setAutoRunActive(boolean value) {
        isAutoRunActive = value;
    }
}
```

### Liskov Substitution Principle (LSP)
`Controller_Frontend` implementiert ein Interface, wodurch die Substituierbarkeit gemäß LSP gewährleistet ist:

```java
public class Controller_Frontend extends PICComponent
implements FrontendControllerInterface { }

public void resetPC() {
    programCounter = 0;
}
```

### Interface Segregation Principle (ISP)
Spezialisierte Interfaces sorgen dafür, dass Klassen nur relevante Funktionen implementieren:

```java
public interface TimerInterface {
    void start();
    void stop();
    int getCurrentTime();
}
```

### Dependency Inversion Principle (DIP)
Zentrale Komponenten wie `PICComponentLocator` und Interfaces lösen die Abhängigkeit von konkreten Klassen:

```java
private PICComponentLocator picComponents;
```

## 2. GRASP-Prinzipien

### Low Coupling
Die Kopplung im Projekt ist durch Verwendung zentraler Zugriffsklassen wie `PICComponentLocator` gering gehalten.

```java
private PICComponentLocator picComponents;
```

### High Cohesion
Funktionen übernehmen jeweils thematisch zusammenhängende Aufgaben:

```java
public static void showStopDialog(String message) {
    Stage stoppedStage = new Stage();
    VBox vbox = new VBox();
    Label grundlabel = new Label("Grund: " + message);
    // GUI-Details ausgelassen
    stoppedStage.show();
}
```

## 3. DRY – Don’t Repeat Yourself
Wiederverwendbare Logik zur Statuskontrolle wurde in `ExecutionState` gekapselt. GUI-Erzeugung findet zentral in `showStopDialog()` statt:

```java
public class ExecutionState {
    private static boolean isSleeping;
    public static boolean isSleeping() { return isSleeping; }
    public static void wakeUp() { isSleeping = false; }
}

private static void showStopDialog(String message) {
    // einmal zentral definierte GUI-Logik
}
