Zusammenfassung Modul 226 B - OOP mit Vererbung
Übersicht
Kompositum
Entwurfsmuster Kompositum
Exception Handling
Fehler-, Ausnahmebehandlung
Unit Tests
JUnit5 Verhaltens- und Grenzwerttests
Entwurfsmuster Kompositum
Fehler-, Ausnahmebehandlung
JUnit5 Verhaltens- und Grenzwerttests
Ist ein Entwurfsmuster aus der Gruppe der Strukturmuster.
Wird zur Darstellung von Teil-Ganzes Hierarchien verwendet.
Das Kompositum wird zum Beispiel bei Dateisystemen, Menüs oder GUIs angewendet.
Es ist vergleichbar mit einer Baumstruktur.
Ist die Basisschnitstelle für alle Objekte.
Implementiert das Standardverhalten der Basiskomponente.
Es enthält keine Verweise auf andere Objekte.
Besitzt Blattelemente. Es implementiert die Methode aus der Basiskomponente und definiert die untergeordneten Operationen.
Hat Zugriff auf die Kompositionselemente über das Komponentenobjekt.
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.
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;
}
}
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;
}
}
}
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);
}
}
}
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("");
}
}
}
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);
}
}
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 -----*/
}
}
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
..
----------
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;
}
}
public class StandardMitarbeiter extends Mitarbeiter {
public StandardMitarbeiter(int id, String name) {
super(id, name);
}
@Override
public void getName() {
System.out.println(super.name);
}
}
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);
}
}
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");
}
}
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");
}
}
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");
}
}
Mitarbeiterliste
----------
Geschaeftsleitung: Hans Muster
Verwaltungsleiterin: Katrin Keller
Mitarbeiter
------------------
Sandra Bischof
------------------
Forschungsleiter: Peter Meier
Mitarbeiter
------------------
Ueli Maurer
Hanspeter Krüsi
------------------
----------
Fehler abfangen und behandeln damit das Programm nicht abstürzt.
Wird ein Fehler in einem Try block generiert wird sofort der entsprechende catch block ausgeführt.
Nach einem try Block muss mindestens ein Catch Block folgen.
Es wird jeweils der erste passende Catch-Block ausgeführt. Spezialisierte Catch Blöcke müssen vor den Allgemeinen definiert werden.
Diese Ausnahme wird ausgelöst, wenn eine Datei nicht existiert, die zum Lesen, Schreiben oder zu anderen Aktivitäten geöffnet werden sollte.
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.
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.
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);
}
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");
}
}
}
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);
}
}
}
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)
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.
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();
}
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...
Bisher wurden die Ausnahmen automatisch “geworfen”. Man kann jedoch auch manuell Ausnahmen mit dem Schlüsselwort throw werfen.
throw new Exception("Exception message");
...
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");
}
...
@Test definiert, dass die folgende Methode eine Testmethode ist.
@Test
void doSomething() {
System.out.println("Do something!");
}
Mit @DisplayName kann der Name der Methode in der JUnit Laufzeitübersicht angepasst werden.
@Test
@DisplayName("printTest")
void printTest() {
System.out.println("Testing");
}
@BeforeEach definiert, dass die folgende Methode vor jeder Testmethode zuerst aufgerufen wird.
@BeforeEach
void init() {
System.out.println("BeforeEach");
}
@AfterEach definiert, dass die folgende Methode nach jeder Testmethode zuerst aufgerufen wird.
@AfterEach
void init() {
System.out.println("AfterEach");
}
AssertEquals wird verwendet, wenn der erwartete Wert sowie der tatsächliche Wert identisch ist.
@Test
void isEqual() {
System.out.println("expected", "actual");
}
AssertNull wird verwendet, wenn überprüft werden soll, ob das Objekt null ist.
@Test
void isEqual() {
System.out.println("expected", "actual");
}
Mit @BeforeAll wird die folgende Methode vor allen Testmethoden durchgeführt.
@BeforeAll
void printTest() {
System.out.println("Run once before all tests");
}
Mit @AfterAll wird die folgende Methode nach allen Testmethoden durchgeführt.
@AfterAll
void printTest() {
System.out.println("Run once after all tests");
}