← Zur Startseite

Klassen & Objektorientierung (OOP)

Objektorientierung ist ein Denkmodell, um Software in Verantwortlichkeiten zu schneiden: Daten (Zustand) und Verhalten (Logik) werden in Objekten gekapselt. Das Ziel ist nicht „mehr Klassen“, sondern verständliche Module, die sich erweitern, testen und sicher betreiben lassen – auch in großen Projekten (Desktop, Web, APIs, KI-Systeme).

Merksatz: Eine gute Klasse ist eine kleine „Mini‑Dienstleistung“: sie hat einen klaren Zweck, eine stabile Schnittstelle und verbirgt Details.

1) Klasse vs. Objekt – das Fundament

Eine Klasse ist der Bauplan: sie definiert Eigenschaften (Felder/Properties) und Methoden (Funktionen). Ein Objekt ist eine konkrete Instanz dieser Klasse zur Laufzeit – mit eigenen Zustandswerten.

Begriff Was ist das? Wozu? Typisches Beispiel
Klasse Bauplan / Typdefinition Wiederverwendbare Struktur & Verhalten beschreiben class User { ... }
Objekt Instanz zur Laufzeit Konkrete Daten + Verhalten nutzen var u = new User(...)
// C# Kurzbeispiel public class User { public string Email { get; } public User(string email) => Email = email; } var user = new User("a@b.de"); // user ist ein Objekt (Instanz)

2) Die 4 OOP‑Prinzipien – in wirklich „nützlich“

Kapselung (Encapsulation)

Kapselung schützt Invarianten: du verhinderst, dass fremder Code deinen Zustand beliebig kaputt macht. Statt „alles public“ gibst du nur die erlaubten Operationen frei.

// Invariante: Kontostand darf nicht negativ werden public class Account { public decimal Balance { get; private set; } public void Deposit(decimal amount) { if (amount <= 0) throw new ArgumentException("amount"); Balance += amount; } public void Withdraw(decimal amount) { if (amount <= 0) throw new ArgumentException("amount"); if (Balance - amount < 0) throw new InvalidOperationException("Insufficient funds"); Balance -= amount; } }

Abstraktion (Abstraction)

Abstraktion blendet Details aus, damit du auf einer höheren Ebene denken kannst: „Sende Nachricht“ statt „öffne Socket, serialisiere JSON, handle Retries …“. Gute Abstraktion ist klein, eindeutig und braucht keine Dokument‑Romanlänge.

Vererbung (Inheritance)

Vererbung modelliert „ist‑ein“ Beziehungen – aber: in der Praxis ist sie schnell überstrapaziert. Verwende sie vorsichtig, besonders bei tiefen Hierarchien. Häufig ist Komposition (Zusammenbauen) stabiler als Vererbung.

Polymorphie (Polymorphism)

Polymorphie bedeutet: du programmierst gegen eine Schnittstelle, nicht gegen eine konkrete Klasse. Dadurch kannst du Implementierungen austauschen (z.B. echte DB vs. Mock) ohne den Aufrufer zu ändern.

// Polymorphie via Interface public interface IClock { DateTime UtcNow { get; } } public sealed class SystemClock : IClock { public DateTime UtcNow => DateTime.UtcNow; } public sealed class FakeClock : IClock { public DateTime UtcNow { get; set; } } public sealed class TokenService { private readonly IClock _clock; public TokenService(IClock clock) => _clock = clock; public string IssueToken() => $"tok_{_clock.UtcNow:yyyyMMddHHmmss}"; }

3) SOLID – die 5 wichtigsten Stabilitätsregeln

SOLID ist kein Dogma, sondern eine „Stabilitäts‑Checkliste“: Sie hilft, dass Änderungen lokal bleiben und nicht das ganze System zerreißen.

Prinzip Worum geht’s? Typische Frage im Review Warnsignal
SRP Eine Klasse hat genau eine Verantwortung „Warum ändert sich diese Klasse?“ Viele Gründe/Features in einer Klasse
OCP Erweiterbar ohne bestehendes Verhalten umzuschreiben „Kann ich neue Variante hinzufügen ohne überall if/else?“ Wachsende Switch/If‑Ketten
LSP Subtypen müssen überall wie Basistyp funktionieren „Überrascht die Subklasse?“ Subklasse wirft „NotSupported“ für geerbte Methoden
ISP Kleine Interfaces statt „Monster‑Interfaces“ „Muss ich Methoden implementieren, die ich nicht brauche?“ Interfaces mit 15+ Methoden
DIP Abhängigkeiten auf Abstraktionen, nicht auf Konkretes „Kann ich austauschen/testen ohne Umbau?“ Überall new SqlConnection() im Code

4) Dependency Injection (DI) – warum das nicht „nur Framework‑Magie“ ist

DI trennt Erzeugung von Nutzung. Deine Business‑Logik bekommt ihre Abhängigkeiten von außen und ist dadurch leichter testbar und austauschbar.

Praxis-Regel: „new“ gehört in die Composition Root (Startup/Program), nicht quer im Code.

// C# Beispiel (Konzept, unabhängig vom konkreten DI-Container) public interface IEmailSender { Task SendAsync(string to, string subject, string body); } public sealed class OrderNotifier { private readonly IEmailSender _email; public OrderNotifier(IEmailSender email) => _email = email; public Task NotifyAsync(string email) => _email.SendAsync(email, "Bestellung", "Danke für deine Bestellung!"); }

5) Architektur: Klassen richtig schneiden (Domain, Application, Infrastructure, UI)

OOP entfaltet ihren Vorteil erst mit sauberer Schichtung. Ein bewährtes Muster:

Schicht Darf abhängen von Darf NICHT Beispiel‑Klassen
Domain Nur Domain DB/HTTP/UI Order, Money, DiscountPolicy
Application Domain + Abstraktionen Konkrete DB‑Treiber direkt CreateOrderHandler, PricingService
Infrastructure Application/Domain (Implementiert Ports) Business‑Regeln „erfinden“ SqlOrderRepository, HttpPaymentClient
UI Application Domain‑Invarianten umgehen ViewModels, Views, Commands

6) Anti‑Patterns: typische Fehler bei Klassen

Diese Muster machen Projekte schnell teuer. Wenn du sie erkennst, kannst du früh gegensteuern:

7) Best Practices: Klassen, die lange gut bleiben

8) Performance: OOP ist nicht automatisch langsam

Performanceprobleme entstehen meist durch I/O, ineffiziente Datenzugriffe oder schlechte Algorithmen – nicht durch „Klassen“. Dennoch helfen ein paar Regeln:

FAQ

Wann ist OOP ideal?

Wenn du eine komplexe Domäne modellierst, mehrere Implementierungen brauchst (z.B. verschiedene Speicher), und wenn Wartbarkeit/Erweiterbarkeit wichtiger sind als „schnellster Prototyp“.

Ist funktionale Programmierung „besser“?

Nicht grundsätzlich. Funktionale Techniken sind oft hervorragend für Datenpipelines und Nebenwirkungs‑Kontrolle. In der Praxis kombinieren Teams häufig beides: OOP für Domänenmodell & Module, funktionale Patterns für Transformationen.

Wie viele Klassen sind „richtig“?

Es gibt keine magische Zahl. Ziel ist: Verantwortlichkeiten klein halten und Änderungen lokal machen. Viele kleine, saubere Klassen sind oft besser als wenige riesige.

Fazit

Klassen und OOP sind am stärksten, wenn sie Verantwortung klar schneiden: Kapselung schützt Invarianten, Polymorphie ermöglicht Austauschbarkeit, SOLID stabilisiert Evolution – und Architektur sorgt dafür, dass Änderungen nicht chaotisch durchs System diffundieren.

Stand: 2026-02-09 · RainbowApex