Modul 226B

OOP mit Vererbung, Klassen-, Objekt- und Sequenzdiagramme

programming illustration

Zusammenfassung Modul 226 B - OOP mit Vererbung

Übersicht

Kompositum

Entwurfsmuster Kompositum

Exception Handling

Fehler-, Ausnahmebehandlung

Unit Tests

JUnit5 Verhaltens- und Grenzwerttests

Kompositum

Kurzfassung

Was ist ein Kompositum?

Ist ein Entwurfsmuster aus der Gruppe der Strukturmuster.
Wird zur Darstellung von Teil-Ganzes Hierarchien verwendet.

Die Struktur

Das Kompositum wird zum Beispiel bei Dateisystemen, Menüs oder GUIs angewendet.
Es ist vergleichbar mit einer Baumstruktur.

Komponente

Ist die Basisschnitstelle für alle Objekte.

Blatt

Implementiert das Standardverhalten der Basiskomponente.
Es enthält keine Verweise auf andere Objekte.

Kompositum

Besitzt Blattelemente. Es implementiert die Methode aus der Basiskomponente und definiert die untergeordneten Operationen.

Client

Hat Zugriff auf die Kompositionselemente über das Komponentenobjekt.

Klassendiagramm

Objektdiagramm

Bestandteile

kompositum uml

Die Komponente ist die Hauptschnittstelle für alle weitere Objekte.
Normalerweise wird eine abstrake Klasse verwendet und dort ein Standardverhalten für alle abgeleiteten Klassen implementiert.

Die Methode Operation ist eine Methode, die alle Klassen implementieren.

Dass Blattobjekt ist das Ende der Komposition. Es enthält keine weitere Objekte mehr.

Die Klasse Kompositum enthält weitere Objekte vom Typ der Basisklasse Komponente.

In der Klasse Kompositum wird eine Liste mit allen enthaltenen Komponenten geführt. Die spezialisierten Klassen können auch neue Methoden sowie Attribute implementieren.

Der Client arbeitet ausschliesslich mit dem Typ Komponente.

Beispiel

Komponente - Department

public abstract class Department {
	
	protected int id;
	protected String name;
	
	public abstract void printDepartmentName();
	
	public Department(int id, String name) {
		this.id = id;
		this.name = name;
	}
}
 

Kompositum - HeadDepartment

import java.util.ArrayList;

public class HeadDepartment extends Department {
	
	private ArrayList<Department> childDepartments;
	
	public HeadDepartment(int id, String name) {
		super(id, name);
		this.childDepartments = new ArrayList<Department>();
	}
	
	
	public void printDepartmentName() {
		childDepartments.forEach(Department::printDepartmentName);
	}
	
	public void addDepartment(Department department) {
		childDepartments.add(department);
	}
	
	public void removeDepartment(Department department) {
		if(childDepartments.contains(department)) {
			childDepartments.remove(department);
		}	
	}
	
	public Department getChildDepartment(int index) {
		if (index >= 0 && index < childDepartments.size()) {
			return childDepartments.get(index);
		} else {
			return null;
		}
	}

}
 

Kompositum - FinancialDepartment

import java.util.ArrayList;

public class FinancialDepartment extends Department {

	ArrayList<Department> childDepartments;
	public FinancialDepartment(int id, String name) {
		super(id, name);
		this.childDepartments = new ArrayList<Department>();
	}
	
	public void printDepartmentName() {
		System.out.println("Department name:\t" + super.name);
		System.out.println("Child departments");
		System.out.println("------------------");
		childDepartments.forEach(Department::printDepartmentName);
		System.out.println("------------------\n");
	}
	
	public void addDepartment(Department department) {
		childDepartments.add(department);
	}
	
	public void removeDepartment(Department department) {
		if(childDepartments.contains(department)) {
			childDepartments.remove(department);
		}	
	}

}
 

Kompositum - SalesDepartment

import java.util.ArrayList;

public class SalesDepartment extends Department {

	ArrayList<Department> childDepartments;
	public SalesDepartment(int id, String name) {
		super(id, name);
		this.childDepartments = new ArrayList<Department>();
	}
	
	
	public void printDepartmentName() {
		System.out.println("Department name:\t" + super.name);
		System.out.println("Child departments");
		System.out.println("------------------");
		childDepartments.forEach(Department::printDepartmentName);
		System.out.println("------------------\n");
	}
	
	
	public void addDepartment(Department department) {
		childDepartments.add(department);
	}
	
	public void removeDepartment(Department department) {
		if(childDepartments.contains(department)) {
			childDepartments.remove(department);
		} else {
			System.out.println("");
		}
	}

}
 

Blatt - DefaultDepartment

public class DefaultDepartment extends Department {

	public DefaultDepartment(int id, String name) {
		super(id, name);
	}
	
	public void printDepartmentName() {
		System.out.println("department name:\t" + super.name);
	}

}
 

Client - MainProgram


public class MainProgram {

	public static void main(String[] args) {
		
		HeadDepartment headDepartment = new HeadDepartment(1, "head department");
		SalesDepartment salesDepartment = new SalesDepartment(1, "sales department");
		FinancialDepartment financialDepartment = new FinancialDepartment(1, "financial department");
		
		/*----- departments hinzufügen -----*/
		
		headDepartment.addDepartment(salesDepartment);
		headDepartment.addDepartment(financialDepartment);
		salesDepartment.addDepartment(new DefaultDepartment(11, "region 11 department"));
		salesDepartment.addDepartment(new DefaultDepartment(8, "region 08 department"));
		salesDepartment.addDepartment(new DefaultDepartment(7, "region 07 department"));
		financialDepartment.addDepartment(new DefaultDepartment(1, "financial department 01"));
		financialDepartment.addDepartment(new DefaultDepartment(2, "financial department 02"));
		
		
		/*----- departments ausgeben -----*/
		System.out.println("Departments");
		System.out.println("----------\n");
		headDepartment.printDepartmentName();
		System.out.println("\n----------\n");
		
		
		/*----- departments entfernen -----*/
		

		
		
		
	}

}
 

Aufgabenstellung

Die Firma Muster AG möchte eine Software für die Mitarbeiterverwaltung.
Die Abteilungen mit den entsprechenden Abteilungsleiter sind wie folgt:

Geschäftsleitung: Hans Muster

Forschungsleiter: Peter Meier

Verwaltungsleiter: Katrin Keller

Die Geschäftsleitung möchte eine Liste der Abteilungen, deren Abteilungsleiter sowie deren Mitarbeiter.

Erstellen Sie ein Programm mit Hilfe des Entwurfsmuster Kompositum sowie gemäss dem Objektdiagramm.

Die Ausgabe könnte zum Beispiel wie folgt aussehen:

Mitarbeiterliste
----------------
Geschäftsleitung:   Name
Verwaltungsleiter:  Name
Mitarbeiter
----------
Name
..
----------
Forschungsleiter:   Name
Mitarbeiter
----------
Name
..
---------- 

Objektdiagramm

Lösungen

Komponente - Mitarbeiter

public abstract class Mitarbeiter {
	protected int id;
	protected String name;
	
	public abstract void getName();
	
	public Mitarbeiter(int id, String name) {
		this.id = id;
		this.name = name;
	}
} 

Blatt - Standardmitarbeiter

public class StandardMitarbeiter extends Mitarbeiter {

	public StandardMitarbeiter(int id, String name) {
		super(id, name);
	}
	
	@Override
	public void getName() {
		System.out.println(super.name);
	}
} 

Kompositum- Geschäftsleitung

import java.util.ArrayList;

public class Geschaeftsleitung extends Mitarbeiter {
	
	private ArrayList<Mitarbeiter> mitarbeiter;
	
	public Geschaeftsleitung(int id, String name) {
		super(id, name);
		this.mitarbeiter = new ArrayList<Mitarbeiter>();
	}
	
	public void addMitarbeiter(Mitarbeiter mitarbeiter) {
		this.mitarbeiter.add(mitarbeiter);
	}
	
	public void removeMitarbeiter(Mitarbeiter mitarbeiter) {
		if(this.mitarbeiter.contains(mitarbeiter)) {
			this.mitarbeiter.remove(mitarbeiter);
		}	
	}
	

	@Override
	public void getName() {
		System.out.println("Geschaeftsleitung:\t" + super.name + "\n");
		this.mitarbeiter.forEach(Mitarbeiter::getName);
		
	}

}
 

Kompositum- Forschung

import java.util.ArrayList;

public class Forschung extends Mitarbeiter {

	ArrayList<Mitarbeiter> mitarbeiter;
	public Forschung(int id, String name) {
		super(id, name);
		this.mitarbeiter = new ArrayList<Mitarbeiter>();
	}
	
	public void addMitarbeiter(Mitarbeiter mitarbeiter) {
		this.mitarbeiter.add(mitarbeiter);
	}
	
	public void removeMitarbeiter(Mitarbeiter mitarbeiter) {
		if(this.mitarbeiter.contains(mitarbeiter)) {
			this.mitarbeiter.remove(mitarbeiter);
		}	
	}

	@Override
	public void getName() {
		System.out.println("Forschungsleiter:\t" + super.name);
		System.out.println("Mitarbeiter");
		System.out.println("------------------");
		this.mitarbeiter.forEach(Mitarbeiter::getName);
		System.out.println("------------------\n");
		
	}

}
 

Kompositum - Verwaltung

import java.util.ArrayList;

public class Verwaltung extends Mitarbeiter {

	ArrayList<Mitarbeiter> mitarbeiter;
	public Verwaltung(int id, String name) {
		super(id, name);
		this.mitarbeiter = new ArrayList<Mitarbeiter>();
	}
	
	public void addMitarbeiter(Mitarbeiter mitarbeiter) {
		this.mitarbeiter.add(mitarbeiter);
	}
	
	public void removeMitarbeiter(Mitarbeiter mitarbeiter) {
		if(this.mitarbeiter.contains(mitarbeiter)) {
			this.mitarbeiter.remove(mitarbeiter);
		}	
	}
	
	@Override
	public void getName() {
		System.out.println("Verwaltungsleiterin:\t" + super.name);
		System.out.println("Mitarbeiter");
		System.out.println("------------------");
		this.mitarbeiter.forEach(Mitarbeiter::getName);
		System.out.println("------------------\n");
		
	}

}
 

MainProgram


public class MainProgram {

	public static void main(String[] args) {
		
		Geschaeftsleitung geschaeftsleitung = new Geschaeftsleitung(1, "Hans Muster");
		Verwaltung verwaltung = new Verwaltung(1, "Katrin Keller");
		Forschung forschung = new Forschung(1, "Peter Meier");
		
		/*----- Mitarbeiter hinzufügen -----*/
		geschaeftsleitung.addMitarbeiter(verwaltung);
		geschaeftsleitung.addMitarbeiter(forschung);
		verwaltung.addMitarbeiter(new StandardMitarbeiter(1, "Sandra Bischof"));
		forschung.addMitarbeiter(new StandardMitarbeiter(1, "Ueli Maurer"));
		forschung.addMitarbeiter(new StandardMitarbeiter(1, "Hanspeter Krüsi"));
		
		
		
		/*----- Mitarbeiter ausgeben -----*/
		System.out.println("Mitarbeiterliste");
		System.out.println("----------\n");
		geschaeftsleitung.getName();
		System.out.println("\n----------\n");
		
		
		
		
		
	}

}
 

Ausgabe

Mitarbeiterliste
----------

Geschaeftsleitung:      Hans Muster

Verwaltungsleiterin:    Katrin Keller
Mitarbeiter
------------------
Sandra Bischof
------------------

Forschungsleiter:	    Peter Meier
Mitarbeiter
------------------
Ueli Maurer
Hanspeter Krüsi
------------------


----------
 

Exception handling

Kurzfassung

Zweck von Exception Handling

Fehler abfangen und behandeln damit das Programm nicht abstürzt.

Try - Catch Block

Wird ein Fehler in einem Try block generiert wird sofort der entsprechende catch block ausgeführt.

Regel 1

Nach einem try Block muss mindestens ein Catch Block folgen.

Regel 2

Es wird jeweils der erste passende Catch-Block ausgeführt. Spezialisierte Catch Blöcke müssen vor den Allgemeinen definiert werden.

Verschiedene Exception Klassen

Diese Ausnahme wird ausgelöst, wenn eine Datei nicht existiert, die zum Lesen, Schreiben oder zu anderen Aktivitäten geöffnet werden sollte.

Weitere Informationen

Die Ausnahme wird ausgelöst, wenn bei der Konvertierung von Zeichen ein Problem auftritt.

Die Ausnahme wird ausgelöst, wenn über das Enderkennungszeichen einer Datei hinaus gelesen werden soll.

Diese Ausnahme wird bei dem Versuch, ein Objekt zu serialisieren, welche die Schnittstelle Serializable nicht implementiert hat, ausgelöst.

Die Ausnahme wird bei einem arithmetischen Fehler ausgelöst. Zum Beispiel wenn ein Integerwert durch null geteilt wird.

Die Ausnahme wird ausgelöst, wenn ein Index von einem Array oder String fehlerhaft benutzt wird. Wenn zum Beispiel Ein Element oberhalb der Grenze angesprochen wird.

Weitere Informationen

 

Die Ausnahme wird dann ausgelöst, wenn statt eines Objektes ein NULL-Verweis benutzt wird.

Wenn ein Zugriff gegen die Sicherheitsregeln erfolgt, dann wird solch eine Ausnahme geworfen.

Try - catch Block

Innerhalb dieses Blocks steht der Code, welcher möglicherweise einen Fehler verursachen kann.

Innerhalb des try Blocks werden die kritischen Anweisungen durchgeführt. Tritt hierhei ein Fehler auf, wird (und nur dann) der Programmcode nach dem Schlüsselwort catch ausgeführt.

Tritt ein Fehler innerhalb des try Blocks auf, wird sofort der Programmcode im catch Block ausgeführt. Der noch nicht durchlaufene Programmcode im try block wird ignoriert!

Try – catch Blöcke werden verwendet, um Fehler abzufangen und dass das Programm somit nicht abstürzt.

try {
    doSomething();
} catch (Exception err) {
    System.out.println("Error: " + err);
} 

Beispiel

Dieses Beispiel liest die Tastatureingabe ein. Dabei wird die Eingabe als Integer der variable x zugewiesen.
Falls die Eingabe keine Zahl ist wird der catch block ausgeführt und der Fehler Ausgegeben.

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) {
		
		int x;
		
		BufferedReader scan = new BufferedReader(new InputStreamReader(System.in));
		try {
			System.out.println("Exception handling\n---------------\n");
			x = Integer.parseInt(scan.readLine());
			System.out.println("Number: " + x);
		}
		catch(Exception err) {
			System.out.println("Inside catch block");
			System.out.println("Error: " + err);
		}
		finally {
			System.out.println("---------------\nEnd of exception handling");
		}
	}

}
 

Catch Blöcke

Um verschiedene Ausnahmen zu behandeln, kann man einfach mehrere catch Blöcke nacheinander hinzufügen. Dabei  wird in der  Klammer die zu behandelnde Exception Klasse angegeben.

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) {
		
		int index;
		int[] values = new int[5];
		FileReader fileReader = null;
		
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		
		System.out.println("Exception handling\n---------------------");
		try {
			System.out.println("Enter an index: ");
			index = Integer.parseInt(bufferedReader.readLine());
			values[index] = 10;
			
			fileReader = new FileReader("C:\\temp\\not-available.txt");
			System.out.println("Closing fileReader...");
			fileReader.close();
		}
		/*----- handle IndexOutOfBoundsException -----*/
		catch (IndexOutOfBoundsException indexException) {
			System.out.println("Wrong index:");
			System.out.println("Error message: " + indexException.getMessage() + "\n");
			
		} 
		/*----- handle FileNotFoundException -----*/
		catch (FileNotFoundException fileException) {
			System.out.println("File not found:");
			System.out.println("Error message: " + fileException.getMessage());
		} 
		/*----- handle other exception -----*/
		catch (Exception err) {
			System.out.println("Other exception:");
			System.out.println("Error message: " + err);
		}
		
	}

}
 

Ausgabe wenn die Zahl 6 eingegeben wird

der Catch block für die IndexOutOfBoundsException wird ausgeführt.

Ausgabe wenn die Zahl 4 eingegeben wird und die Datei nicht vorhanden ist

der Catch block für die FileNotFoundException wird ausgeführt.
Exception handling
---------------------
Enter an index: 6
Wrong index:
Error message: Index 6 out of bounds for length 5
 
Exception handling
---------------------
Enter an index: 4
File not found:
Error message: C:\temp\not-available.txt 
(The system cannot find the file specified) 

Ausgabe wenn die Zahl 20.5 eingegeben wird

der Catch block für die other exception wird ausgeführt.

Ausgabe wenn die Zahl 2 eingegeben wird und die Datei vorhanden ist

Es wurde kein Fehler generiert.
Exception handling
---------------------
Enter an index: 20.5
Other exception:
Error message: java.lang.NumberFormatException:
For input string: "20.5"
 
Exception handling
---------------------
Enter an index: 2
Closing fileReader... 

Achtung: Der Programmcode innerhalb von dem try Block wird bei einem Fehler nicht weiter ausgeführt!
In diesem Beispiel wird der
FileReader bei einem Fehler nie geschlossen. Um dies zu beheben gibt es einen zusätzlichen Block – den finally block.

Finally Block

Der finally Block wird immer ausgeführt. Egal ob ein Fehler generiert wurde oder nicht.

try {
    doSomething();
} catch (Exception err) {
    System.out.println("Error: " + err);
} finally {
    runEverytime();
} 

Angepasstes Beispiel mit finally Block

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) {
		
		int index;
		int[] values = new int[5];
		FileReader fileReader = null;
		
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		
		System.out.println("Exception handling\n---------------------");
		try {
			System.out.println("Enter an index: ");
			index = Integer.parseInt(bufferedReader.readLine());
			values[index] = 10;
			
			fileReader = new FileReader("C:\\temp\\not-available.txt");
			System.out.println("Closing fileReader...");
			fileReader.close();
		}
		/*----- handle IndexOutOfBoundsException -----*/
		catch (IndexOutOfBoundsException indexException) {
			System.out.println("Wrong index:");
			System.out.println("Error message: " + indexException.getMessage() + "\n");
			
		} 
		/*----- handle FileNotFoundException -----*/
		catch (FileNotFoundException fileException) {
			System.out.println("File not found:");
			System.out.println("Error message: " + fileException.getMessage());
		} 
		/*----- handle other exception -----*/
		catch (Exception err) {
			System.out.println("Other exception:");
			System.out.println("Error message: " + err);
		}
		/*----- finally block -----*/
		finally {
			try {
				if(fileReader != null) {
					System.out.println("Closing fileReader...");
					fileReader.close();
				}

			} catch (IOException err) {
				System.out.println("Exception in finally block");
				System.out.println("Error message: " + err);
			}
		}
		
	}

}
 

Nun wird der FileReader im finally block geschlossen falls dieser nicht null ist.

Exception handling
---------------------
Enter an index: 2
Closing fileReader...
 

Throwing exceptions

Bisher wurden die Ausnahmen automatisch “geworfen”. Man kann jedoch auch manuell Ausnahmen mit dem Schlüsselwort throw werfen.

throw new Exception("Exception message"); 

Beispiel

...
System.out.println("Exception handling\n---------------------");
try {
	System.out.println("Enter an index: ");
	index = Integer.parseInt(bufferedReader.readLine());
	
	/*----- throw new exception -----*/
	if(index == 10) throw new Exception("Custom exception, input value: 10");
	
	values[index] = 10;

	fileReader = new FileReader("C:\\\\Users\\\\marco\\\\Downloads\\\\TE Module 1_Excel.pdf");
}
... 

Unit Tests

@Test

@Test definiert, dass die folgende Methode eine Testmethode ist.

@Test
void doSomething() {
    System.out.println("Do something!");
} 

@DisplayName

Mit @DisplayName kann der Name der Methode in der JUnit Laufzeitübersicht angepasst werden.

@Test
@DisplayName("printTest")
void printTest() {
	System.out.println("Testing");
} 

@BeforeEach

@BeforeEach definiert, dass die folgende Methode vor jeder Testmethode zuerst aufgerufen wird.

@BeforeEach
void init() {
    System.out.println("BeforeEach");
} 

@AfterEach

@AfterEach definiert, dass die folgende Methode nach jeder Testmethode zuerst aufgerufen wird.

@AfterEach
void init() {
    System.out.println("AfterEach");
} 

Assertions

assertEquals

AssertEquals wird verwendet, wenn der erwartete Wert sowie der tatsächliche Wert identisch ist.

@Test
void isEqual() {
	System.out.println("expected", "actual");
} 

assertNull

AssertNull wird verwendet, wenn überprüft werden soll, ob das Objekt null ist.

@Test
void isEqual() {
	System.out.println("expected", "actual");
} 

@BeforeAll

Mit @BeforeAll wird die folgende Methode vor allen Testmethoden durchgeführt.

@BeforeAll
void printTest() {
	System.out.println("Run once before all tests");
} 

@AfterAll

Mit @AfterAll wird die folgende Methode nach allen Testmethoden durchgeführt.

@AfterAll
void printTest() {
	System.out.println("Run once after all tests");
} 
Scroll to Top