RU | EN | DE

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

Kriteriumabstract classinterface
VererbungNur eine (Java unterstützt Single Inheritance)Mehrere Interfaces können implementiert werden
Zustand (Felder)Kann normale Felder (inkl. protected/private) habenNur public static final (Konstanten)
MethodenKann implementierte und abstrakte Methoden enthaltenVor Java 8 nur abstrakte; danach auch default und static
KonstruktorKann einen Konstruktor haben (für Unterklassen)Kann keinen Konstruktor haben
Wann verwendenWenn gemeinsamer Zustand und teilweise Implementierung benötigt werdenWenn Verhalten (Vertrag) für verschiedene Klassen festgelegt werden soll
Beispiel AnwendungBasisklasse Animal, von der Dog, Cat geerbt werdenInterface 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

PrinzipWo es in Spring/Java vorkommt
SSchichtentrennung: Controller / Service / Repository
OErweiterbare Interfaces, Strategy-Pattern
LKorrekte Hierarchie von DTO und Entity
IKleine Interfaces: CrudRepository, JpaRepository
DDependency Injection (Spring IoC Container)