Part 11

Klassendiagramme

Ein Klassendiagramm ist ein Diagramm, das in der Softwareentwicklung und -modellierung verwendet wird, um Klassen und deren Beziehungen zu beschreiben. Klassendiagramme ermöglichen es uns, Software auf einem hohen Abstraktionsniveau zu modellieren, ohne den Quellcode betrachten zu müssen.

Klassen in einem Klassendiagramm entsprechen den Klassen im Quellcode. Das Diagramm zeigt die Namen und Attribute der Klassen, Verbindungen zwischen den Klassen und manchmal auch die Methoden der Klassen.

Im Folgenden machen wir uns mit der Erstellung und dem Lesen von Klassendiagrammen unter Verwendung von UML vertraut. Die Verwendung einer einheitlichen Modellierungssprache stellt sicher, dass Klassendiagramme, die von verschiedenen Personen gezeichnet werden, von allen, die mit der Sprache vertraut sind, gelesen und verstanden werden können.

Beschreibung von Klassen und Klassenattributen

Zunächst beschreiben wir eine Klasse und deren Attribute. Unten ist der Quellcode für eine Klasse namens Person dargestellt, die zwei Klassenattribute name und age hat.

public class Person {
    private String name;
    private int age;
}

In einem Klassendiagramm wird eine Klasse durch ein Rechteck dargestellt, wobei der Name der Klasse oben steht. Eine Linie unter dem Klassennamen trennt diesen von der Liste der Attribute (Namen und Typen der Klassenvariablen). Die Attribute werden zeilenweise aufgelistet.

In einem Klassendiagramm werden Klassenattribute als "attributeName: attributeType" notiert. Ein + vor dem Attributnamen bedeutet, dass das Attribut öffentlich ist, und ein -, dass es privat ist.

[Person|-name:String;-age:int]

Beschreibung des Klassenkonstruktors

Im Folgenden haben wir den Quellcode für einen Konstruktor der Person-Klasse hinzugefügt. Der Konstruktor erhält den Namen der Person als Parameter.

public class Person {
    private String name;
    private int age;

    public Person(String initialName) {
        this.name = initialName;
        this.age = 0;
    }
}

In einem Klassendiagramm listen wir den Konstruktor (und alle anderen Methoden) unter den Attributen auf. Eine Linie unterhalb der Attributliste trennt diese von der Methodenliste. Methoden werden mit +/- (abhängig von der Sichtbarkeit der Methode), dem Methodennamen, den Parametern und deren Typen notiert. Der oben stehende Konstruktor wird als +Person(initialName:String) dargestellt.

Die Parameter werden auf die gleiche Weise notiert wie die Klassenattribute: "parameterName: parameterType".

[Person|-name:String;-age:int|+Person(initialName:String)]

Beschreibung von Klassenmethoden

Im Folgenden haben wir der Person-Klasse eine Methode printPerson(), die void zurückgibt, hinzugefügt.

public class Person {
    private String name;
    private int age;

    public Person(String initialName) {
        this.name = initialName;
        this.age = 0;
    }

    public void printPerson() {
        System.out.println(this.name + ", age " + this.age + " years");
    }
}

In einem Klassendiagramm werden alle Klassenmethoden einschließlich der Konstruktoren aufgelistet; Konstruktoren werden zuerst und dann alle Klassenmethoden aufgelistet. Wir schreiben auch den Rückgabetyp einer Methode im Klassendiagramm.

[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void]

Im Folgenden haben wir der Person-Klasse die Methode getName hinzugefügt, die den Namen der Person zurückgibt.

public class Person {
    private String name;
    private int age;

    public Person(String initialName) {
        this.name = initialName;
        this.age = 0;
    }

    public void printPerson() {
        System.out.println(this.name + ", age " + this.age + " years");
    }

    public String getName() {
        return this.name;
    }
}
[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String]
Loading
Loading

Verbindungen zwischen Klassen

In einem Klassendiagramm werden die Verbindungen zwischen Klassen durch Pfeile dargestellt. Die Pfeile zeigen auch die Richtung der Verbindung an.

Im Folgenden haben wir eine Klasse Book.

public class Book {
    private String name;
    private String publisher;

    // constructors and methods
}
[Book|-name:String;-publisher:String]

Wenn wir dem Quellcode eine Variable author, deren Typ Person ist, hinzufügen, wird die Variable wie alle anderen Klassenvariablen deklariert.

public class Book {
    private String name;
    private String publisher;
    private Person author;

    // constructors and methods
}

In einem Klassendiagramm werden Variablen, die auf andere Objekte verweisen, nicht zusammen mit den anderen Klassenattributen notiert, sondern als Verbindungen zwischen den Klassen dargestellt. Im untenstehenden Klassendiagramm haben wir die Klassen Person und Book sowie die Verbindung zwischen ihnen.

[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String][Book]-author->[Person]

Der Pfeil zeigt die Richtung der Verbindung an. Die oben gezeigte Verbindung zeigt, dass ein Book seinen Autor kennt, eine Person jedoch nichts über die Bücher weiß, deren Autor sie ist. Wir können dem Pfeil auch eine Beschriftung hinzufügen, um die Verbindung zu beschreiben. Im obigen Diagramm ist dem Pfeil eine Beschriftung hinzugefügt, die uns mitteilt, dass ein Book einen Autor hat.

Wenn ein Buch mehrere Autoren hat, werden die Autoren in einer Liste gespeichert.

public class Book {
    private String name;
    private String publisher;
    private ArrayList<Person> authors;

    // constructors and methods
}

In einem Klassendiagramm wird diese Situation durch das Hinzufügen eines Sterns am Ende des Pfeils, der die Verbindung zwischen den Klassen zeigt, beschrieben. Der Stern sagt uns, dass ein Book zwischen 0 und einer unbegrenzten Anzahl von Autoren haben kann. Im folgenden Diagramm haben wir keine Beschriftung hinzugefügt, um die Multiplizität der Verbindung zu beschreiben, aber es wäre aus Gründen der Klarheit eine gute Idee.

[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String][Book]-*->[Person]

Klassenmethoden werden genauso beschrieben wie zuvor. Unten haben wir der Book-Klasse die Methoden getAuthors und addAuthor hinzugefügt.

public class Book {
    private String name;
    private String publisher;
    private ArrayList<Person> authors;

    // constructor

    public ArrayList<Person> getAuthors() {
        return this.authors;
    }

    public void addAuthor(Person author) {
        this.authors.add(author);
    }
}
[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String|+getAuthors():ArrayList;+addAuthor(author:Person)][Book]-*->[Person]

Wir könnten den Typ der Elemente in der ArrayList ArrayList<Person> und eine Beschriftung, die die Verbindung beschreibt, "authors" in das obige Klassendiagramm aufnehmen.

Loading

Wenn keine Pfeilspitze in einer Verbindung vorhanden ist, wissen beide Klassen voneinander. Unten ist ein Beispiel, bei dem ein Buch über seinen Autor Bescheid weiß und eine Person über ein Buch, das sie geschrieben hat.

[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String|+getAuthors():ArrayList;+addAuthor(author:Person)][Book]-*[Person]
public class Person {
    private String name;
    private int age;
    private Book book;

    // ...
}
public class Book {
    private String name;
    private String publisher;
    private ArrayList<Person> authors;

    // ..
}

Wie Sie sehen können, ist die Verbindung standardmäßig — wenn kein Stern auf der Verbindung vorhanden ist — singulär. Die oben dargestellten Klassen sind interessant, da eine Person nur ein Book haben kann.

Wenn eine Person mehrere Bücher haben kann und ein Buch mehrere Autoren haben kann, fügen wir an beiden Enden der Verbindung einen Stern hinzu:

[Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String|+getAuthors():ArrayList;+addAuthor(author:Person)][Book]*-*[Person]

Nun würde die Person-Klasse wie folgt aussehen:

import java.util.ArrayList;

public class Person {
    private String name;
    private int age;
    private ArrayList<Book> books;

    // ...
}
Loading

Beschreibung von Vererbung

In einem Klassendiagramm wird Vererbung durch einen Pfeil mit einem dreieckigen Kopf beschrieben. Das Dreieck zeigt auf die Klasse, von der geerbt wird. Im folgenden Beispiel erbt die Klasse Engine von der Klasse Part.

[Part|-id:String;-manufacturer:String;-description:String][Engine|-type:String][Part]^-[Engine]

Im folgenden Beispiel beschreibt das Klassendiagramm die Klassen aus der Übung ProductWarehouseWithHistory. Die Klasse ProductWarehouseWithHistory erbt von der Klasse ProductWarehouse, die wiederum von der Klasse Warehouse erbt. ChangeHistory ist eine separate Klasse, die mit ProductWarehouse verbunden ist. ProductWarehouseWithHistory kennt die ChangeHistory, aber die ChangeHistory kennt ProductWarehouseWithHistory nicht.

[Warehouse|-capacity:double;-balance:double|+Warehouse(capacity:double);+getBalance():double;+getCapacity():double;+howMuchSpaceLeft():double;+addToWarehouse(amount:double):void;+takeFromWarehouse(amount:double):double;+toString():String][ProductWarehouse|-name:String|+ProductWarehouse(name:String، capacity:double);+getName():String;+setName(name:String):String;+toString():String][ChangeHistory|-states:ArrayList|+ChangeHistory();+add(status:double);+clear():void;...][ProductWarehouseWithHistory||+ProductWarehouseWithHistory(name:String، capacity:double، initialBalance:double);+history():String;+printAnalysis():void;+addToWarehouse(amount:double);+takeFromWarehouse(amount:double):double][Warehouse]^-[ProductWarehouse][ProductWarehouse]^-[ProductWarehouseWithHistory][ChangeHistory]<-[ProductWarehouseWithHistory]

Vererbung von abstrakten Klassen wird fast genauso beschrieben wie die von regulären Klassen. Allerdings fügen wir über dem Namen der Klasse die Beschreibung <<abstract>> hinzu. Der Name der Klasse und ihre abstrakten Methoden werden ebenfalls kursiv geschrieben.

part11 1 classdiagram abstracts
Loading

Beschreibung von Schnittstellen

In Klassendiagrammen werden Schnittstellen als <<interface>> NameOfTheInterface notiert. Im Folgenden beschreiben wir eine Schnittstelle Readable.

public interface Readable {

}
[<<interface>> Readable]

Methoden werden genauso beschrieben wie bei einer Klasse.

Die Implementierung einer Schnittstelle wird durch einen gestrichelten Pfeil mit einem dreieckigen Kopf dargestellt. Im Folgenden beschreiben wir eine Situation, in der Book die Schnittstelle Readable implementiert.

[<<interface>> Readable][Book]-.-^[<<interface>> Readable]
Loading
Loading
Sie haben das Ende dieses Abschnitts erreicht! Weiter zum nächsten Abschnitt: