4.6.5 Struktur durch klare Methoden und Klassen – Prinzip der Verantwortung

In der objektorientierten Programmierung ist es ein wichtiges Prinzip: eine Methode – eine Aufgabe. Das bedeutet: Jede Methode soll genau für das zuständig sein, was ihr Name verspricht – nicht mehr und nicht weniger.

Das erhöht die Lesbarkeit, erleichtert spätere Änderungen und fördert sauberen Code („Clean Code“). Dieses Prinzip wird auch als Single Responsibility Principle bezeichnet.


🚲 Beispiel: Fahrrad mit klaren Zuständigkeiten

Wir bauen eine Klasse Fahrrad, die genau zwei Methoden hat:

  • fahren() verändert den Zustand (mehr Kilometer)
  • zeigeKm() zeigt den aktuellen Kilometerstand
# Fahrrad-Klasse mit geschützten Attributen
# J. Thomaschewski, 29.07.2025

class Fahrrad:
    def __init__(self):
        self.__km = 0

    def fahren(self, strecke):
        self.__km += strecke

    def zeigeKm(self):
        print(f"Gefahrene Kilometer: {self.__km}")

# Hauptprogramm
bike = Fahrrad()
bike.fahren(12)
bike.zeigeKm()

Ausgabe:
Gefahrene Kilometer: 12


💡 Guter Stil – Praktisches Beispiel mit Display

In dieser Übung prüfen wir die Textlänge, bevor etwas auf ein OLED-Display ausgegeben wird. Die Logik wird dabei sauber von der Anzeige getrennt. Auch hier nutzen wir private Attribute im CamelCase-Stil.

# Textlänge prüfen und anzeigen (OLED)
# Praktikumsbeispiel – J. Thomaschewski, 29.07.2025

from machine import Pin, SoftI2C
from ssd1306 import SSD1306_I2C

# OLED initialisieren
i2c = SoftI2C(scl=Pin(17), sda=Pin(16))
oled = SSD1306_I2C(128, 64, i2c, addr=0x3C)

class Eingabe:
    def __init__(self, maxLaenge):
        self.__maxLaenge = maxLaenge

    def pruefeText(self, text):
        if len(text) <= self.__maxLaenge:
            return text
        else:
            return "Text ist zu lang!"

# Hauptprogramm
eingabe = Eingabe(16)
text = input("Gib deinen Text ein: ")
anzeigeText = eingabe.pruefeText(text)

oled.fill(0)
oled.text(anzeigeText, 0, 20)
oled.show()

Wichtig

🧠 Merksatz: Eine Methode soll eine Aufgabe haben. Wenn wir beim Erklären einer Methode das Wort „und“ verwenden, ist sie wahrscheinlich zu lang oder falsch aufgeteilt.

Aufgabe – Methoden aufteilen

Ergänze die Klasse Fahrrad um eine Methode resetKm(), die den Kilometerstand wieder auf null setzt. Gib den Kilometerstand vor und nach dem Reset aus.

Lösungsvorschlag
class Fahrrad:
    def __init__(self):
        self.__km = 0

    def fahren(self, strecke):
        self.__km += strecke

    def zeigeKm(self):
        print(f"Gefahrene Kilometer: {self.__km}")

    def resetKm(self):
        self.__km = 0

bike = Fahrrad()
bike.fahren(25)
bike.zeigeKm()
bike.resetKm()
bike.zeigeKm()

Ausgabe:
Gefahrene Kilometer: 25
Gefahrene Kilometer: 0


🔍 Strukturierung von Klassen – was eine gute Klasse ausmacht

Nachdem wir uns mit dem Aufbau und der Zuständigkeit einzelner Methoden beschäftigt haben, wollen wir jetzt betrachten, was eine gut strukturierte Klasse ausmacht.

Eine Klasse sollte so gestaltet sein, dass sie:

  • eine klar umrissene Aufgabe erfüllt,
  • alle notwendigen Daten (Attribute) zur Bearbeitung dieser Aufgabe enthält,
  • und nur Methoden anbietet, die zum Arbeiten mit genau diesen Daten benötigt werden.

Wir sprechen dabei auch von einer logischen Kapselung: Daten und Funktionen, die zusammengehören, sollen auch im Code zusammenbleiben.

Beispiele für gut strukturierte Klassen

Klasse Aufgabe Sinnvolle Methoden
Konto Kontostand verwalten einzahlen(), abheben(), zeigeStand()
Fahrrad Gefahrene Kilometer zählen und zurücksetzen fahren(), zeigeKilometer(), zuruecksetzen()
Ampel Steuerung eines einfachen Ampelablaufs start(), wechsleZuRot(), wechsleZuGruen()

Wichtig: Eine Klasse sollte nicht zu viele unterschiedliche Aufgaben übernehmen. Wenn eine Klasse plötzlich Benutzereingaben verarbeitet, LEDs steuert und Daten speichert, ist sie zu breit aufgestellt. Solche Aufgaben gehören in verschiedene Klassen.

Wichtig

🧠 Merksatz: Eine Klasse sollte eine Aufgabe haben – und nur das tun, was zu dieser Aufgabe gehört.

Wenn wir nun wissen, was eine gute Klasse ausmacht, gehen wir auf die nächste Strukturebene und fassen gleichartige Klassen zusammen.

✨ Model - View - Controler (MVC-Konzept)

Das Model-View-Controller (MVC)-Konzept ist ein bewährtes Entwurfsmuster in der Softwareentwicklung, das Klassen in drei Gruppen unterteilt:

  1. Model (Modell): Das Model ist für die Datenhaltung zuständig. Hierin finden sich Klassen zum Speichern und Abrufen der Daten. Da das Model unabhängig von der Verarbeitung der Daten (Controler) und der Ansicht der Daten (View) ist, kann man in einer guten Programmierung die Datenhaltung ändern, ohne dass dies einen Einfluss auf die Datenverarbeitung bzw. die Darstellung der Daten hat.

  2. View (Ansicht): In den Klassen des Views findet die Darstellung der Anwendung sowie die Interaktionen Darstellung der Benutzerinteraktionen statt.

  3. Controller (Steuerung): Der Controller fungiert als Vermittler zwischen Model und View. Er verarbeitet Benutzereingaben, aktualisiert das Modell entsprechend und sorgt dafür, dass die Ansicht die aktuellen Daten anzeigt.

Durch diese Trennung der Verantwortlichkeiten fördert das MVC-Muster eine klare Strukturierung des Codes, erleichtert die Wartung und ermöglicht eine parallele Entwicklung der einzelnen Komponenten. In Python wird dieses Muster häufig in Web-Frameworks wie Django verwendet, um eine saubere und skalierbare Anwendungsarchitektur zu gewährleisten.