Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

Entwurfsprinzipien für Klassen

Nach dieser Lektion: Ich kann Code erkennen, der einer Klasse zwei Aufgaben gibt oder sich schwer erweitern lässt.

Lektion, 60 Min.4 BefehleLab „Linux im Alltag“: die dreißig Befehle, die Entwickelnde auswendig tippen

Eine Klasse, die rechnet, formatiert und speichert

Ein Entwurfsprinzip ist eine Faustregel, die Klassen leichter änderbar macht. Zwei davon gehören zum Werkzeug jeder Entwicklerin und jedes Entwicklers: eine Verantwortung je Klasse und offen für Erweiterung.

Ein Notenbericht rechnet einen Durchschnitt, macht daraus Text und legt ihn ab. Wer nur den Text ändern will, muss eine Klasse öffnen, die auch rechnet und speichert. Dabei geht schnell etwas kaputt.

Am Ende dieser Lektion

Notiz

Ich kann Code erkennen, der einer Klasse zwei Aufgaben gibt oder sich schwer erweitern lässt.

Schlüsselwörter

BegriffWas er bedeutet
Verantwortungeine Aufgabe, für die eine Klasse allein zuständig ist
Änderungsgrundein Wunsch, der eine Klasse ändern muss
Kohäsionwie eng die Teile einer Klasse zusammengehören
Erweiterungneues Verhalten, das neuen Code statt Änderungen braucht
Schnittstelledie Methoden, die andere aufrufen dürfen

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Eine Klasse hat nur einen Änderungsgrund

Das Prinzip der einzigen Verantwortung lautet: Eine Klasse hat genau eine Aufgabe und damit genau einen Änderungsgrund. Der Notenbericht hat drei: die Rechnung, den Text und die Ablage.

Jede Änderung an einer Aufgabe kann die beiden anderen stören, weil sie im selben Code stehen.

Ein Bericht mit drei Aufgaben

Code: python
class Notenbericht:
    def __init__(self, noten):
        self.noten = noten

    def durchschnitt(self):
        summe = 0
        for note in self.noten:
            summe = summe + note
        return summe // len(self.noten)

    def als_text(self):
        return "Schnitt: " + str(self.durchschnitt())

    def speichern(self, ablage):
        ablage.append(self.als_text())

ablage = []
bericht = Notenbericht([12, 8, 10])
bericht.speichern(ablage)
print(ablage)
# Diese Klasse hat drei Gründe, sich zu ändern. Welche?

Welche Klasse sich bei welchem Wunsch ändert

WunschVorherNach dem Aufteilen
Der Schnitt soll anders gerechnet werdenNotenberichtRechner
Der Text soll kürzer seinNotenberichtTextform
Die Ablage soll in eine Datei schreibenNotenberichtAblage

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Ein häufiger Fehler

Warnung

Viele glauben, eine Verantwortung sei eine einzelne Methode, und zerlegen alles in Klassen mit je einer Zeile. Eine Verantwortung ist ein Änderungsgrund, kein Methodenzähler. Eine Klasse darf viele Methoden haben, solange alle derselben Aufgabe dienen.

Neues Verhalten soll neuen Code brauchen, keine Änderung

Das zweite Prinzip heißt offen für Erweiterung, geschlossen für Änderung. Neues Verhalten kommt durch eine neue Klasse hinzu. Die alte Klasse bleibt unberührt.

Der aufgeteilte Bericht ruft nur als_text auf. Eine neue Textform mit derselben Methode passt ohne Eingriff in Bericht.

Aufgeteilt: eine neue Textform ohne Eingriff

Code: python
class Rechner:
    def durchschnitt(self, noten):
        return sum(noten) // len(noten)

class Langtext:
    def als_text(self, wert):
        return "Schnitt: " + str(wert)

class Kurztext:
    def als_text(self, wert):
        return str(wert)

class Bericht:
    def __init__(self, rechner, textform):
        self.rechner = rechner
        self.textform = textform

    def erstellen(self, noten):
        wert = self.rechner.durchschnitt(noten)
        return self.textform.als_text(wert)

print(Bericht(Rechner(), Langtext()).erstellen([12, 8, 10]))
print(Bericht(Rechner(), Kurztext()).erstellen([12, 8, 10]))

Die Aufgaben einer Klasse im Lab zählen

Im Lab schreiben Sie die Klasse Notenbericht in die Datei bericht.py. Danach fragen Sie mit grep, welche Methoden sie hat.

Der Befehl grep -o zeigt nur den Teil der Zeile, der zum Muster passt. So erscheint pro Methode eine kurze Zeile: erst def __init__, dann die drei Aufgaben.

Den Ordner anlegen

Befehl
mkdir -p ~/oop-labor

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Hineingehen

Befehl
cd ~/oop-labor

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Die Klasse mit drei Aufgaben schreiben

Befehl
printf 'class Notenbericht:\n    def __init__(self, noten):\n        self.noten = noten\n\n    def durchschnitt(self):\n        return sum(self.noten) // len(self.noten)\n\n    def als_text(self):\n        return "Schnitt: " + str(self.durchschnitt())\n\n    def speichern(self, ablage):\n        ablage.append(self.als_text())\n' > bericht.py

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Die Methoden der Klasse auflisten

Befehl
grep -o 'def [a-z_]*' bericht.py

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Drei Aufgaben stehen in einer Klasse

Die Ausgabe nennt vier Zeilen: def __init__, def durchschnitt, def als_text und def speichern. Die erste richtet das Objekt ein, die anderen drei sind die Aufgaben.

Rechnen, Formatieren und Speichern haben nichts miteinander zu tun. Das ist der Hinweis, dass die Klasse in drei zerfallen sollte.

Über dieses Lab und seinen Quellcode: Lab „Linux im Alltag“: die dreißig Befehle, die Entwickelnde auswendig tippen

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.