CodeGym /Kurse /JAVA 25 SELF /Beispiele für den Aufbau von Abstraktionen in realen Aufg...

Beispiele für den Aufbau von Abstraktionen in realen Aufgaben

JAVA 25 SELF
Level 19, Lektion 3
Verfügbar

1. Abstraktion in realen Anwendungen: warum sie nötig ist

In den vorherigen Vorlesungen haben wir bereits den Begriff der Abstraktion kennengelernt und einfache Beispiele betrachtet. Jetzt schauen wir, wie dieser Ansatz in realeren Aufgaben funktioniert. In realen Projekten hat man fast immer mit unterschiedlichen, aber ähnlichen Objekten zu tun. Zum Beispiel verschiedene Zahlungsarten, verschiedene Verkehrsmittel, verschiedene Formen in einem Grafikeditor. Ohne Abstraktion wird der Code schnell zu einer Sammlung aus „if-else“ und Copy-and-Paste. Mit Abstraktion hingegen – alles ist streng, schön und vor allem bequem für Weiterentwicklung und Wartung.

Abstraktion ermöglicht:

  • Implementierungsdetails zu verbergen: mit Objekten über eine gemeinsame Schnittstelle arbeiten, ohne sich dafür zu interessieren, wie sie innen aufgebaut sind.
  • Code-Duplikate zu vermeiden: gemeinsames Verhalten und Felder werden in die Basisklasse ausgelagert.
  • Das System leicht zu erweitern: das Hinzufügen neuer Objektarten erfordert kein Umschreiben des alten Codes.
  • Den Code flexibel zu machen: man kann eine Implementierung durch eine andere ersetzen, ohne den Rest des Systems zu ändern.

Schauen wir uns einige Beispiele aus verschiedenen Bereichen an.

2. Beispiel 1: Zahlungssysteme

Aufgabenstellung

Angenommen, Sie schreiben ein Modul für einen Online-Shop. Ihre Aufgabe ist es, verschiedene Zahlungsarten zu verarbeiten: Kreditkarte, PayPal, Kryptowährung. Alle sollen „eine Zahlung verarbeiten“ können, aber die Details sind jeweils unterschiedlich.

Abstraktion: Klasse Payment

public abstract class Payment {
    protected double amount;

    public Payment(double amount) {
        this.amount = amount;
    }

    // Abstrakte Methode: Wie die Zahlung konkret verarbeitet wird – entscheiden die Subklassen
    public abstract void process();

    // Allgemeine Methode für alle Zahlungen
    public void printAmount() {
        System.out.println("Zahlungsbetrag: " + amount + " Rubel.");
    }
}

Konkrete Implementierungen

public class CreditCardPayment extends Payment {
    private String cardNumber;

    public CreditCardPayment(double amount, String cardNumber) {
        super(amount);
        this.cardNumber = cardNumber;
    }

    @Override
    public void process() {
        System.out.println("Verarbeitung der Kartenzahlung: " + cardNumber);
        // Hier könnte eine Bankintegration stehen :)
    }
}
public class PaypalPayment extends Payment {
    private String email;

    public PaypalPayment(double amount, String email) {
        super(amount);
        this.email = email;
    }

    @Override
    public void process() {
        System.out.println("Verarbeitung der PayPal-Zahlung für das Konto: " + email);
        // Und hier – Aufruf des PayPal-API
    }
}
public class CryptoPayment extends Payment {
    private String walletAddress;

    public CryptoPayment(double amount, String walletAddress) {
        super(amount);
        this.walletAddress = walletAddress;
    }

    @Override
    public void process() {
        System.out.println("Verarbeitung der Krypto-Zahlung an die Wallet: " + walletAddress);
        // Hier könnte Blockchain-Magie stehen
    }
}

Nutzung der Abstraktion

import java.util.*;

public class PaymentDemo {
    public static void main(String[] args) {
        List<Payment> payments = new ArrayList<>();
        payments.add(new CreditCardPayment(1500.0, "1234 5678 9012 3456"));
        payments.add(new PaypalPayment(500.0, "user@example.com"));
        payments.add(new CryptoPayment(0.05, "0xABCD..."));

        for (Payment payment : payments) {
            payment.printAmount();
            payment.process();
            System.out.println("---");
        }
    }
}

Ausgabe:

Zahlungsbetrag: 1500.0 Rubel.
Verarbeitung der Kartenzahlung: 1234 5678 9012 3456
---
Zahlungsbetrag: 500.0 Rubel.
Verarbeitung der PayPal-Zahlung für das Konto: user@example.com
---
Zahlungsbetrag: 0.05 Rubel.
Verarbeitung der Krypto-Zahlung an die Wallet: 0xABCD...
---

Vorteile:

  • Man kann eine neue Zahlungsart hinzufügen, ohne den alten Code zu ändern (z. B. Apple Pay).
  • Der Code, der mit Zahlungen arbeitet, hängt nicht von deren konkretem Typ ab.
  • Gemeinsame Logik (z. B. das Ausgeben des Betrags über printAmount()) ist an einer Stelle implementiert.

3. Beispiel 2: Transport

Aufgabenstellung

In einem Spiel oder einer Simulation gibt es verschiedene Arten von Verkehrsmitteln: Autos, Fahrräder, Züge. Alle können sich „bewegen“, tun dies aber auf unterschiedliche Weise. Manche müssen betankt werden, andere nicht.

Abstraktion: Klasse Transport

public abstract class Transport {
    protected String name;

    public Transport(String name) {
        this.name = name;
    }

    public abstract void move();

    // Nicht alle Verkehrsmittel müssen betankt werden, standardmäßig: nein
    public void fuelUp() {
        System.out.println(name + ": Tanken ist nicht erforderlich.");
    }
}

Konkrete Implementierungen

public class Car extends Transport {
    public Car(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " fährt auf der Straße.");
    }

    @Override
    public void fuelUp() {
        System.out.println(name + ": wir tanken Benzin.");
    }
}
public class Bicycle extends Transport {
    public Bicycle(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " tritt in die Pedale.");
    }
    // fuelUp wird nicht überschrieben – ein Fahrrad muss nicht betankt werden
}
public class Train extends Transport {
    public Train(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " rast auf den Schienen.");
    }

    @Override
    public void fuelUp() {
        System.out.println(name + ": wir tanken Diesel oder Strom.");
    }
}

Nutzung der Abstraktion

import java.util.*;

public class TransportDemo {
    public static void main(String[] args) {
        List<Transport> vehicles = Arrays.asList(
            new Car("Toyota"),
            new Bicycle("Stels"),
            new Train("Sapsan")
        );

        for (Transport t : vehicles) {
            t.move();
            t.fuelUp();
            System.out.println("---");
        }
    }
}

Ausgabe:

Toyota fährt auf der Straße.
Toyota: wir tanken Benzin.
---
Stels tritt in die Pedale.
Stels: Tanken ist nicht erforderlich.
---
Sapsan rast auf den Schienen.
Sapsan: wir tanken Diesel oder Strom.
---

Vorteile:

  • Man kann jedes Verkehrsmittel identisch verarbeiten, ohne seinen Typ zu prüfen.
  • Es ist einfach, eine neue Art von Transport hinzuzufügen (z. B. E-Scooter).

4. Beispiel 3: Grafikeditor

Aufgabenstellung

Sie schreiben einen Mini-Grafikeditor. Darin gibt es Linien, Ellipsen, Polygone – und all das sind „Formen“, die man zeichnen und in der Größe verändern kann. Dabei implementiert jede Form diese Aktionen auf ihre Weise.

Abstraktion: Klasse Figure

public abstract class Figure {
    protected String color = "black";

    public abstract void draw();

    public abstract void resize(double factor);

    public void setColor(String color) {
        this.color = color;
    }
}

Konkrete Implementierungen

public class Line extends Figure {
    private double length;

    public Line(double length) {
        this.length = length;
    }

    @Override
    public void draw() {
        System.out.println("Wir zeichnen eine Linie mit der Länge " + length + " in der Farbe " + color);
    }

    @Override
       public void resize(double factor) {
        length *= factor;
        System.out.println("Neue Linienlänge: " + length);
    }
}
public class Ellipse extends Figure {
    private double a, b;

    public Ellipse(double a, double b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public void draw() {
        System.out.println("Wir zeichnen eine Ellipse mit den Achsen " + a + " und " + b + " in der Farbe " + color);
    }

    @Override
    public void resize(double factor) {
        a *= factor;
        b *= factor;
        System.out.println("Neue Ellipsenmaße: " + a + " x " + b);
    }
}
public class Polygon extends Figure {
    private int sides;

    public Polygon(int sides) {
        this.sides = sides;
    }

    @Override
    public void draw() {
        System.out.println("Wir zeichnen ein Polygon mit " + sides + " Seiten in der Farbe " + color);
    }

    @Override
    public void resize(double factor) {
        System.out.println("Wir ändern die Größe des Polygons mit " + sides + " Seiten um " + factor);
    }
}

Nutzung der Abstraktion

import java.util.*;

public class EditorDemo {
    public static void main(String[] args) {
        List<Figure> figures = new ArrayList<>();
        figures.add(new Line(10));
        figures.add(new Ellipse(5, 3));
        figures.add(new Polygon(6));

        for (Figure f : figures) {
            f.setColor("green");
            f.draw();
            f.resize(2);
            System.out.println("---");
        }
    }
}

Ausgabe:

Wir zeichnen eine Linie mit der Länge 10.0 in der Farbe green
Neue Linienlänge: 20.0
---
Wir zeichnen eine Ellipse mit den Achsen 5.0 und 3.0 in der Farbe green
Neue Ellipsenmaße: 10.0 x 6.0
---
Wir zeichnen ein Polygon mit 6 Seiten in der Farbe green
Wir ändern die Größe des Polygons mit 6 Seiten um 2.0
---

Vorteile:

  • Alle Formen können in einer Liste gespeichert und identisch verarbeitet werden.
  • Es ist einfach, eine neue Form hinzuzufügen (z. B. einen Stern oder ein Herz).
  • Gemeinsame Methoden (z. B. das Setzen der Farbe über setColor()) sind einmal implementiert.

5. Wie Abstraktion hilft, Code zu vereinfachen

In jedem der obigen Beispiele gibt es ein gemeinsames Schema:

  • Die abstrakte Basisklasse definiert den Vertrag (was ein Objekt kann).
  • Konkrete Unterklassen implementieren die Details.
  • Der Code, der mit der Abstraktion arbeitet, hängt nicht vom Objekttyp ab, wodurch das System flexibel und erweiterbar wird.

Vergleichstabelle der Ansätze

Ohne Abstraktion (if-else) Mit Abstraktion (OOP)
Viele Typprüfungen Neuer Typ – wir ändern den Code
Duplizierte Logik Logik – an einem Ort
Schwer zu erweitern Hinzufügen – leicht
Schwer zu testen Implementierungen leicht austauschbar

6. Typische Fehler beim Entwerfen von Abstraktionen

Fehler Nr. 1: Abstraktion um der Abstraktion willen.
Wenn Sie nur einen Objekttyp haben und keine Erweiterung geplant ist, ist eine abstrakte Klasse nicht nötig. Man sollte den Code nicht ohne Grund verkomplizieren.

Fehler Nr. 2: Zu allgemeine Abstraktion.
Wenn die Basisklasse zu „verwässert“ ist, haben die Unterklassen nichts gemeinsam außer dem Namen. Zum Beispiel die Abstraktion „Thing“ für alles Mögliche. Das erschwert die Wartung und das Verständnis des Codes.

Fehler Nr. 3: Code-Duplikation in Unterklassen.
Wenn alle Unterklassen dieselbe Implementierung einer Methode haben, sollte man sie in die Basisklasse verschieben (nicht abstrakt machen).

Fehler Nr. 4: Verstoß gegen das Prinzip „vom Allgemeinen zum Speziellen“.
Wenn in der abstrakten Klasse Details auftauchen, die nur eine Unterklasse braucht, ist die Abstraktion falsch gewählt.

Fehler Nr. 5: Abstrakte Methoden zu implementieren vergessen.
Wenn man nicht alle abstrakten Methoden in der Unterklasse implementiert, zwingt der Compiler dazu, die Klasse ebenfalls abstrakt zu machen. Manchmal ist das überraschend :)

1
Aufgabe
JAVA 25 SELF, Level 19, Lektion 3
Gesperrt
Flächenberechnung in einer Grafikapplikation 🎨
Flächenberechnung in einer Grafikapplikation 🎨
1
Aufgabe
JAVA 25 SELF, Level 19, Lektion 3
Gesperrt
Universelles Benachrichtigungssystem 📧💬
Universelles Benachrichtigungssystem 📧💬
1
Aufgabe
JAVA 25 SELF, Level 19, Lektion 3
Gesperrt
Flottenverwaltung des Unternehmens 🚚🚲
Flottenverwaltung des Unternehmens 🚚🚲
1
Aufgabe
JAVA 25 SELF, Level 19, Lektion 3
Gesperrt
Bestellverarbeitungsmodul im Einzelhandel 🛒
Bestellverarbeitungsmodul im Einzelhandel 🛒
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION