Informatik

Implementationsdiagramme

In der Einführungsphase hast du Klassendiagramme gezeichnet, um deine Entwürfe festzuhalten. Sie waren eine Skizze: „Es gibt ein Konto, das hat einen Besitzer und einen Kontostand."

Für eine Skizze reicht das. Für eine Klassenarbeit nicht – und für jemanden, der deinen Entwurf umsetzen soll, auch nicht. Denn aus „hat einen Kontostand" folgt weder, ob der Kontostand ein int oder ein double ist, noch ob man ihn von außen verändern darf.

Zwei Stufen der Genauigkeit

  • Ein Entwurfsdiagramm entsteht früh im Modellierungsprozess. Es nennt Klassen und Beziehungen, oft ohne Datentypen und ohne Sichtbarkeiten. Es beantwortet die Frage: Woraus besteht das System?
  • Ein Implementationsdiagramm ist vollständig. Es nennt zu jedem Attribut den Datentyp, zu jeder Methode die Parameter mit Typ und den Rückgabetyp, und zu jedem Element die Sichtbarkeit. Es beantwortet die Frage: Wie sieht der Quelltext aus?

Aus einem Implementationsdiagramm lässt sich das Klassengerüst ohne Rückfragen schreiben – und umgekehrt. Genau das ist der Prüfstein: Wer beim Übersetzen ins Java noch etwas erfinden muss, hat kein Implementationsdiagramm vor sich.

Weitere Darstellungsformen findest du unter Objektorientierte Modellierung.

Die Notation

classDiagram
    class Konto {
        -besitzer: String
        -kontostand: double
        +Konto(pBesitzer: String)
        +getBesitzer() String
        +getKontostand() double
        +zahleEin(pBetrag: double)
        +hebeAb(pBetrag: double) boolean
        #korrigiere(pNeuerStand: double)
    }

Ein Klassenkasten hat drei Felder: Name, Attribute, Methoden.

Zeichen Bedeutung in Java
- nur in dieser Klasse sichtbar private
# auch in den Unterklassen sichtbar protected
+ überall sichtbar public

Geschrieben wird

  • ein Attribut als sichtbarkeit name: typ,
  • eine Methode als sichtbarkeit name(parameter: typ): rückgabetyp.

Der Datentyp steht also immer hinter dem Doppelpunkt – beim Attribut, beim Parameter und beim Rückgabewert.

Ein Konstruktor heißt wie die Klasse und hat keinen Rückgabetyp. Eine Methode ohne Rückgabewert bekommt auch keinen: Bei ihr endet die Zeile hinter der Klammer, das void aus dem Java-Quelltext taucht im Diagramm nicht auf.

Die Reihenfolge name: typ ist die in Nordrhein-Westfalen übliche und zugleich die der UML. In manchen Büchern steht stattdessen typ name – so herum, wie es im Java-Quelltext aussieht. Beides meint dasselbe; halte dich an die Schreibweise, die deine Lehrkraft benutzt, und mische sie nicht.

Beziehungen gehören dazu

Ein Diagramm mit einer einzigen Klasse ist selten. Sobald mehrere Klassen zusammenspielen, gehören auch die Beziehungen hinein.

classDiagram
    class Bank {
        -name: String
        -konten: Konto[]
        -anzahl: int
        +Bank(pName: String, pMaxKonten: int)
        +eroeffne(pKonto: Konto) boolean
        +gesamtvermoegen() double
    }
    class Konto {
        -besitzer: String
        -kontostand: double
        +Konto(pBesitzer: String)
        +getKontostand() double
    }
    class Girokonto {
        -dispolimit: double
        +Girokonto(pBesitzer: String, pDispolimit: double)
    }
    Bank "1" --> "0..*" Konto : verwaltet
    Konto <|-- Girokonto
Linie Bedeutung im Quelltext
durchgezogener Pfeil mit offener Spitze Assoziation – „kennt", „hat" ein Attribut vom Typ der anderen Klasse
durchgezogener Pfeil mit leerem Dreieck Vererbung – „ist ein" extends

An eine Assoziation schreibt man die Kardinalität: 1 an das eine Ende, 0..* an das andere heißt „eine Bank verwaltet beliebig viele Konten, jedes Konto gehört zu genau einer Bank".

Geerbte Attribute und Methoden werden im Unterklassenkasten nicht wiederholt – dafür ist der Pfeil da. Im Kasten steht nur das, was neu dazukommt oder überschrieben wird.

Vom Diagramm zum Quelltext

Das Diagramm oben ergibt Zeile für Zeile diesen Quelltext. Vergleiche beim Lesen jede Java-Zeile mit ihrer Entsprechung im Kasten.

Was das Diagramm nicht sagen kann. Dass negative Beträge ignoriert werden und dass nur abgehoben werden darf, was da ist, steht nirgends im Kasten – nur im Quelltext und im Kommentar darüber.

Deshalb gehört zu einem Entwurf immer beides: das Diagramm für den Aufbau und eine kurze Beschreibung je Methode für die Bedeutung. Genau das nennt der Lehrplan „Klassen dokumentieren".


Teil 1: Lesen

Aufgabe 1: Vom Quelltext zum Diagramm

Ohne Rechner. Zeichne auf Papier das vollständige Implementationsdiagramm zur folgenden Klasse. Trage alles ein, was hineingehört – und nur, was hineingehört.

public class Spielfigur {
 
    private String name;
    private int leben;
    private double x;
    private double y;
    protected boolean unverwundbar;
 
    public Spielfigur(String pName) {
        name = pName;
        leben = 3;
        unverwundbar = false;
    }
 
    public String getName() {
        return name;
    }
 
    public int getLeben() {
        return leben;
    }
 
    public void bewege(double pDx, double pDy) {
        x = x + pDx;
        y = y + pDy;
    }
 
    public boolean erleideSchaden(int pMenge) {
        if (unverwundbar) {
            return false;
        }
        leben = leben - pMenge;
        pruefeLeben();
        return true;
    }
 
    private void pruefeLeben() {
        if (leben < 0) {
            leben = 0;
        }
    }
}
Tipp: die vier Stolpersteine

Geh die Klasse Zeile für Zeile durch und frag dich bei jeder Zeile: Steht das schon in meinem Kasten?

Vier Dinge werden regelmäßig vergessen: eine Methode, ein Sichtbarkeitszeichen, ein paar Datentypen und die Klammern hinter einem Namen.

Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Aufgabe 2: Diagramm und Quelltext passen nicht zusammen

Ohne Rechner. Jemand hat zuerst das Diagramm gezeichnet und dann den Quelltext geschrieben – dabei sind vier Abweichungen entstanden.

Finde alle vier. Notiere zu jeder: Was steht im Diagramm, was im Quelltext? Entscheide danach für jede Abweichung, welche der beiden Seiten du ändern würdest, und begründe es in einem Satz.

classDiagram
    class Buch {
        -titel: String
        -seiten: int
        -ausgeliehen: boolean
        +Buch(pTitel: String, pSeiten: int)
        +getTitel() String
        +getSeiten() int
        +istAusgeliehen() boolean
        +leiheAus() boolean
        +gibZurueck()
        -protokolliere(pAktion: String)
    }
public class Buch {
 
    private String titel;
    public int seiten;
    private boolean ausgeliehen;
 
    public Buch(String pTitel, int pSeiten) {
        titel = pTitel;
        seiten = pSeiten;
        ausgeliehen = false;
    }
 
    public String getTitel() {
        return titel;
    }
 
    public boolean istAusgeliehen() {
        return ausgeliehen;
    }
 
    public boolean leiheAus() {
        if (ausgeliehen) {
            return false;
        }
        ausgeliehen = true;
        return true;
    }
 
    public void gibZurueck(String pName) {
        ausgeliehen = false;
    }
 
    public void protokolliere(String pAktion) {
        IO.println(pAktion);
    }
}
Tipp: geh in vier Runden vor

Vergleiche nicht alles auf einmal, sondern viermal die ganze Klasse:

  1. Gibt es jedes Element beider Seiten auf der anderen Seite auch?
  2. Stimmen die Sichtbarkeiten?
  3. Stimmen die Datentypen – bei Attributen, Rückgaben und Parametern?
  4. Stimmen die Parameterlisten?
Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Teil 2: Schreiben

Aufgabe 3: Vom Diagramm zum Quelltext

Setze das folgende Implementationsdiagramm um, bis alle Tests grün sind. Achte auf jede Angabe: Sichtbarkeiten, Datentypen, Rückgabetypen.

classDiagram
    class Rechteck {
        -breite: double
        -hoehe: double
        +Rechteck(pBreite: double, pHoehe: double)
        +getBreite() double
        +getHoehe() double
        +flaeche() double
        +umfang() double
        +istQuadrat() boolean
        +verdoppleSeiten()
        #skaliere(pFaktor: double)
    }

Was ein Diagramm nicht sagen kann und deshalb hier danebensteht:

  • Der Konstruktor setzt Seiten, die kleiner oder gleich 0 sind, auf 1.
  • istQuadrat liefert true, wenn beide Seiten gleich lang sind.
  • skaliere multipliziert beide Seiten mit dem Faktor – aber nur, wenn dieser positiv ist.
  • verdoppleSeiten benutzt skaliere mit dem Faktor 2 und rechnet nicht selbst.
Tipp 1: die Attribute

Im Diagramm stehen zwei Zeilen mit -. Daraus wird im Quelltext:

private double breite;

Die zweite schreibst du selbst.

Tipp 2: skaliere ist protected

# im Diagramm heißt protected. Das Gerüst gibt das schon so vor – ändere es nicht auf public.

Genau deshalb ruft der Test skaliere auch nicht direkt auf: Von außen ist die Methode gar nicht sichtbar. Er geht über verdoppleSeiten(), und diese Methode ruft von innen auf:

skaliere(2.0);

Das ist der übliche Umgang mit protected und private: Solche Methoden sind Werkzeuge der Klasse für sich selbst und für ihre Unterklassen.

Tipp 3: die Mindestseite

Für jede Seite dieselbe Prüfung, zweimal hingeschrieben:

if (pBreite <= 0) {
    breite = 1.0;
} else {
    breite = pBreite;
}
Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Zum Weiterdenken

Vertiefung 1: Was ein Diagramm verschweigt

Zwei Programmiererinnen bekommen dasselbe Implementationsdiagramm von Rechteck – ohne die drei Sätze, die in Aufgabe 3 danebenstanden. Beide setzen es korrekt um, und ihre Klassen verhalten sich trotzdem verschieden.

a) Nenne drei Stellen, an denen die beiden Umsetzungen auseinandergehen können, obwohl beide zum Diagramm passen.

b) Ein Diagramm kann diese Lücke grundsätzlich nicht schließen. Warum nicht? Was wäre der Preis, wenn man es versuchte?

c) Womit schließt man sie stattdessen? Nenne zwei Mittel, die du in diesem Lernpfad schon benutzt hast.

d) Beurteile: Wenn man die Lücke ohnehin anders schließen muss – wozu dann überhaupt ein Diagramm?

Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Vertiefung 2: Der eigene Entwurf im Rückspiegel

Nimm dir das Spiel oder das Projekt vor, das du am Ende der Einführungsphase gebaut hast.

a) Zeichne nachträglich das vollständige Implementationsdiagramm – mit allen privaten Methoden, allen Datentypen und allen Beziehungen zwischen den Klassen.

b) Vergleiche es mit dem Entwurf von damals. Was ist beim Programmieren dazugekommen, was hast du weggelassen?

c) Suche im Diagramm nach den Stellen, die dir jetzt nicht mehr gefallen: ein public, das private sein könnte; eine Klasse, die zu viel weiß; eine Methode, die in der falschen Klasse steht.

d) Beurteile: Hätte ein genaueres Diagramm dir Arbeit erspart – oder wärst du damit nur langsamer losgekommen? Es gibt auf diese Frage keine allgemein richtige Antwort, aber eine begründete.


Selbsttest

Implementationsdiagramme

Teilbare URL erstellen

Abschnitte auswählen