Einkapselung
Wir verstecken Felder und geben den Zugriff nur über Methoden frei.
class BankAccount {
private double balance;
public void deposit(double amount) { balance += amount; }
public void withdraw(double amount) {
if (amount <= balance) balance -= amount;
else throw new IllegalArgumentException("Недостаточно средств");
}
public double getBalance() { return balance; }
}
class Main {
public static void main(String[] args) {
BankAccount acc = new BankAccount();
acc.deposit(100);
acc.withdraw(40);
System.out.println(acc.getBalance()); // 60.0
}
}Vererbung
class Animal {
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override
void sound() { System.out.println("Woof!"); }
}
class Main {
public static void main(String[] args) {
Animal a = new Dog();
a.sound(); // Woof!
}
}Abstraktion
abstract class Shape {
abstract double area();
}
class Circle extends Shape {
double r;
Circle(double r) { this.r = r; }
@Override double area() { return Math.PI * r * r; }
}
class Main {
public static void main(String[] args) {
Shape s = new Circle(3);
System.out.println(s.area()); // 28.27
}
}Polymorphismus
interface Payment {
void pay(double amount);
}
class CardPayment implements Payment {
public void pay(double amount) {
System.out.println("Pay by card: " + amount);
}
}
class CashPayment implements Payment {
public void pay(double amount) {
System.out.println("Pay by cash: " + amount);
}
}
class Main {
public static void main(String[] args) {
Payment p = new CardPayment();
p.pay(100); // Pay by card: 100
}
}Unterschied zwischen abstract class und interface
📘 Definitionen
abstract class ist eine Klasse, die nicht direkt erstellt werden kann (über new), aber sie kann sowohl implementierte Methoden als auch abstrakte (ohne Körper) enthalten.
Sie wird verwendet für gemeinsame Logik und Zustand, die von Kindklassen geerbt werden sollen.
interface ist ein Vertrag (eine Sammlung von Methoden), der Verhalten garantiert, aber keinen Zustand (vor Java 8).
Moderne Interfaces (ab Java 8+) können enthalten:
default-Methoden (mit Implementierung),static-Methoden,private-Methoden (ab Java 9).
📗 Wichtige Unterschiede
| Kriterium | abstract class | interface |
|---|---|---|
| Vererbung | Nur eine (Java unterstützt Single Inheritance) | Mehrere Interfaces können implementiert werden |
| Zustand (Felder) | Kann normale Felder (inkl. protected/private) haben | Nur public static final (Konstanten) |
| Methoden | Kann implementierte und abstrakte Methoden enthalten | Vor Java 8 nur abstrakte; danach auch default und static |
| Konstruktor | Kann einen Konstruktor haben (für Unterklassen) | Kann keinen Konstruktor haben |
| Wann verwenden | Wenn gemeinsamer Zustand und teilweise Implementierung benötigt werden | Wenn Verhalten (Vertrag) für verschiedene Klassen festgelegt werden soll |
| Beispiel Anwendung | Basisklasse Animal, von der Dog, Cat geerbt werden | Interface Comparable<T> oder Serializable |
// Abstract class — has common state
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public abstract void makeSound();
public void sleep() {
System.out.println(name + " is sleeping...");
}
}
// Interface — defines behavior
public interface Flyable {
void fly();
}
// Class inheriting from abstract and implementing interface
public class Bird extends Animal implements Flyable {
public Bird(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " chirps");
}
@Override
public void fly() {
System.out.println(name + " flies away!");
}
}💡 Fazit:
- Eine abstrakte Klasse beschreibt, was ein Objekt ist.
- Ein Interface beschreibt, was ein Objekt tun kann.
SOLID-Prinzipien
SOLID ist eine Sammlung von 5 Designprinzipien, die dabei helfen, flexiblen, lesbaren und wartbaren Code zu erstellen.
Sie werden in der objektorientierten Programmierung (OOP) und der Anwendungsarchitektur verwendet, insbesondere in Spring, DDD und der Clean Architecture.
S — Single Responsibility Principle
Wesensgehalt:
Eine Klasse sollte nur einen Grund für eine Änderung haben, das heißt, sie sollte nur eine einzige Aufgabe erfüllen.
Schlecht:
class UserService {
void registerUser(User user) { ... }
void sendEmail(User user) { ... }
}Gud:
class UserService {
void registerUser(User user) { ... }
}
class EmailService {
void sendEmail(User user) { ... }
}📍 In Spring angewendet:
Controller, Service, Repository — jede Klasse ist für ihre eigene Schicht verantwortlich.
O — Open/Closed Principle
Wesensgehalt:
Klassen sollten für Erweiterungen offen, aber für Änderungen geschlossen sein.
→ Es ist besser, neue Klassen hinzuzufügen, als alte zu verändern.
Beispiel:
interface Payment {
void pay();
}
class CardPayment implements Payment { ... }
class PaypalPayment implements Payment { ... }
class ApplePay implements Payment { ... }
// Class uses an interface, not a specific implementation
class PaymentProcessor {
void process(Payment payment) {
payment.pay();
}
}📍 Wird angewendet bei der Implementierung von Abhängigkeiten (Dependency Injection).
L — Liskov Substitution Principle
Wesensgehalt:
Objekte von Unterklassen sollten durch Objekte der Oberklasse ersetzt werden können, ohne das Verhalten des Programms zu verändern.
Falsch:
class Bird { void fly() { ... } }
class Penguin extends Bird {
void fly() { throw new UnsupportedOperationException(); }
}Ein Pinguin ist ein Vogel, aber er fliegt nicht → das verstößt gegen das Prinzip.
Lösung:
Das Flyable-Interface auslagern und Komposition statt Vererbung verwenden.
I — Interface Segregation Principle
Wesensgehalt:
Clients sollten nicht von Methoden abhängen, die sie nicht verwenden.
Es ist besser, viele kleine Interfaces zu haben als ein großes.
Schlecht:
interface Worker {
void work();
void eat();
}
class Robot implements Worker {
public void work() {}
public void eat() {} // cannot eat
}Gut:
interface Workable { void work(); }
interface Eatable { void eat(); }
class Robot implements Workable { public void work() {} }
class Human implements Workable, Eatable { ... }📍 Wird angewendet beim Entwurf von APIs und Microservices.
D — Dependency Inversion Principle
Wesensgehalt:
Hochrangige Module sollten nicht von niederrangigen Modulen abhängen – beide sollten von Abstraktionen abhängen.
Schlecht:
class MySQLDatabase { void connect() { ... } }
class UserRepository {
private MySQLDatabase db = new MySQLDatabase(); // tight coupling
}Gut (über ein Interface):
interface Database { void connect(); }
class MySQLDatabase implements Database { ... }
class PostgreSQLDatabase implements Database { ... }
class UserRepository {
private final Database db;
public UserRepository(Database db) { this.db = db; }
}📍 In Spring wird dies durch Dependency Injection umgesetzt (@Autowired, @Service, @Repository).
🧩 Anwendung von SOLID in einer echten Java-Architektur
| Prinzip | Wo es in Spring/Java vorkommt |
|---|---|
| S | Schichtentrennung: Controller / Service / Repository |
| O | Erweiterbare Interfaces, Strategy-Pattern |
| L | Korrekte Hierarchie von DTO und Entity |
| I | Kleine Interfaces: CrudRepository, JpaRepository |
| D | Dependency Injection (Spring IoC Container) |