Java Fortgeschrittenen Schulung – Kursbezug
Ziel dieses Kapitels: Sie bauen OOP-Strukturen, die erweiterbar sind (neue Varianten ohne Umbau) und können Ihre Wahl (Abstraktion, Interface, Vererbung) begründen.
Worum geht’s?
- Abstraktion: Was ist Kernlogik, was ist Detail?
- Interfaces: Verträge definieren (was kann ein Objekt?), unabhängig von Implementierung.
- Vererbung & Polymorphie: Gemeinsame Basen nutzen – aber Overuse vermeiden.
- Komposition statt Vererbung als Standard-Reflex (wenn es „has-a“ ist).
Lehr-/Lernziele
- (LZ1) zwischen Interface, abstrakter Klasse und Vererbung unterscheiden und die passende Wahl begründen.
- (LZ2) Polymorphie so einsetzen, dass neue Varianten ohne Änderung an bestehender Logik hinzugefügt werden können (Open/Closed als Praxisintuition).
- (LZ3) Komposition gezielt einsetzen (z.B. Regeln/Services), statt Vererbung für „has-a“ zu missbrauchen.
Interface als Vertrag (stabil, austauschbar)
public interface Preisregel {
double anwenden(double grundpreis);
}
public class KeinRabatt implements Preisregel {
public double anwenden(double grundpreis) { return grundpreis; }
}
public class OnlineRabatt10 implements Preisregel {
public double anwenden(double grundpreis) { return grundpreis * 0.90; }
}Abstrakte Klasse für gemeinsamen Code
Wenn mehrere Schulungsarten gemeinsame Felder/Logik haben, aber Details variieren, passt eine abstrakte Basis.
public abstract class Schulung {
protected final String titel;
protected final int tage;
protected final double grundpreis;
protected Schulung(String titel, int tage, double grundpreis) {
this.titel = titel;
this.tage = tage;
this.grundpreis = grundpreis;
}
public abstract String ortLabel();
public String zusammenfassung() {
return titel + " | " + tage + " Tage | Ort: " + ortLabel();
}
}
public class OnlineSchulung extends Schulung {
public OnlineSchulung(String titel, int tage, double grundpreis) {
super(titel, tage, grundpreis);
}
public String ortLabel() { return "online"; }
}
public class PraesenzSchulung extends Schulung {
private final String stadt;
public PraesenzSchulung(String titel, int tage, double grundpreis, String stadt) {
super(titel, tage, grundpreis);
this.stadt = stadt;
}
public String ortLabel() { return stadt; }
}Polymorphie: gleiche API, verschiedene Umsetzung
public class Demo {
public static void main(String[] args) {
Schulung s1 = new OnlineSchulung("Java Fortgeschritten (SemaTrain)", 5, 2082.50);
Schulung s2 = new PraesenzSchulung("Java Fortgeschritten (SemaTrain)", 5, 2082.50, "Hamburg");
System.out.println(s1.zusammenfassung());
System.out.println(s2.zusammenfassung());
}
}Komposition statt Vererbung (Standardwahl)
Wenn eine Schulung etwas „hat“ (z.B. Preisregel, Validator, Logger), ist Komposition meist besser als Vererbung.
public class BuchungsService {
private final Preisregel preisregel;
public BuchungsService(Preisregel preisregel) {
this.preisregel = preisregel;
}
public double endpreis(double grundpreis) {
return preisregel.anwenden(grundpreis);
}
}
public class Anwendungsfall {
public static void main(String[] args) {
BuchungsService online = new BuchungsService(new OnlineRabatt10());
BuchungsService praesenz = new BuchungsService(new KeinRabatt());
System.out.println("Online-Endpreis: " + online.endpreis(2082.50));
System.out.println("Praesenz-Endpreis: " + praesenz.endpreis(2082.50));
}
}Praxisaufgabe (Mini)
- Erstellen Sie ein Interface
NachrichtenFormatierermitString formatieren(String text). - Implementieren Sie zwei Varianten:
KlartextFormatiererundGrossbuchstabenFormatierer. - Bauen Sie einen
BenachrichtigungsService, der einen Formatierer per Konstruktor bekommt (Komposition). - Geben Sie 2 Nachrichten aus – einmal klar, einmal in Großbuchstaben.
Lösung anzeigen
public interface NachrichtenFormatierer {
String formatieren(String text);
}
public class KlartextFormatierer implements NachrichtenFormatierer {
public String formatieren(String text) { return text; }
}
public class GrossbuchstabenFormatierer implements NachrichtenFormatierer {
public String formatieren(String text) { return text.toUpperCase(); }
}
public class BenachrichtigungsService {
private final NachrichtenFormatierer formatierer;
public BenachrichtigungsService(NachrichtenFormatierer formatierer) {
this.formatierer = formatierer;
}
public void senden(String nachricht) {
System.out.println(formatierer.formatieren(nachricht));
}
}
public class DemoPraxis {
public static void main(String[] args) {
BenachrichtigungsService klar = new BenachrichtigungsService(new KlartextFormatierer());
BenachrichtigungsService gross = new BenachrichtigungsService(new GrossbuchstabenFormatierer());
klar.senden("Kurs: Java Fortgeschritten (SemaTrain) | Ort: online");
gross.senden("Hinweis: Bitte Technik-Check durchführen");
}
}Optional: typische Stolperfallen
- Vererbung für „has-a“: Service/Regel als Feld (Komposition), nicht als Basisklasse.
- Zu breite Basisklassen: Abstrakte Klasse nur für echten gemeinsamen Kern.
- Zu viele Mini-Interfaces: lieber wenige, klare Verträge als „Interface-Explosion“ ohne Nutzen.
Kurz-Takeaways
- Interface = stabiler Vertrag, Implementierung austauschbar.
- Abstrakte Klasse = gemeinsamer Kern + Variationen in Unterklassen.
- Polymorphie = gleiche Nutzung, andere Umsetzung zur Laufzeit.
- Komposition bevorzugen, wenn es „hat-eine“-Beziehung ist.