Begriff
SOLID Principles
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
5 Regeln für guten OOP-Code (von Uncle Bob). Wenn du sie befolgst, ist dein Code leicht zu ändern. Wenn nicht, ist jeder Bugfix ein Albtraum ("Spaghetti-Code").
- S: Eine Klasse macht nur EINE Sache.
- O: Schreib neuen Code dazu, statt alten zu ändern.
- L: Ersetzen muss funktionieren (keine bösen Überraschungen).
- I: Kleine Interfaces sind besser als große.
- D: Verlasse dich auf Verträge (Abstraktion), nicht auf Details.
Merksatz: Ein Akronym für fünf Designprinzipien der objektorientierten Programmierung, die Software verständlicher, flexibler und wartbarer machen.
Das wichtigste Prinzip: Single Responsibility (SRP).
Falsch: User-Klasse, die login(), saveToDb() und sendEmail() hat.
Richtig:
User(Daten)AuthService(Login)UserRepository(DB)EmailService(Email) Änderst du die Datenbank, musst du den Email-Code nicht anfassen.
1. Open/Closed Principle (OCP)
"Offen für Erweiterung, geschlossen für Änderung."
Du willst Rabatte berechnen.
Schlecht: if (type == 'student') ... else if (type == 'senior'). Jedes Mal, wenn ein neuer Rabatt kommt, musst du die alte Funktion ändern (Risiko!).
Gut: Interface DiscountStrategy. Du erstellst eine neue Klasse SeniorDiscount. Das alte System lädt sie automatisch. Du fasst den alten Code nie an.
2. Liskov Substitution Principle (LSP)
Das "Ente"-Problem.
Wenn Ente von Vogel erbt, aber Ente.fliegen() einen Fehler wirft (weil sie krank ist), verletzt das LSP.
Derjenige, der Vogel nutzt, erwartet, dass er fliegt.
Code, der instanceof Checks braucht, verletzt oft LSP.
3. Dependency Inversion Principle (DIP)
High-Level-Code (Geschäftslogik) darf nicht von Low-Level-Code (MySQL-Treiber) abhängen.
Beide sollen von Abstraktionen abhängen.
Nicht: Controller -> MySQLDatabase.
Sondern: Controller -> DatabaseInterface <- MySQLDatabase.
So kannst du MySQL gegen Postgres tauschen, ohne den Controller zu ändern.
Das DIP und Inversion of Control (IoC)
Das Dependency Inversion Principle fordert Verträge (Interfaces) zwischen Logik und Treiber. Doch wie bekommt der Controller zur Laufzeit die richtige MySQL-Instanz übergeben, ohne new MySQL() zu tippen (was die Inversion sofort wieder zerstören würde)?
Die Antwort sind IoC Container (Dependency Injection Frameworks wie Spring Boot oder NestJS).
Beim Start der App registriert sich MySQL im Singleton-Pool des Containers. Der Controller sagt nur: @Inject DatabaseInterface db. Der Container (die Magie im Hintergrund) sucht automatisch die passende Klasse und injiziert die Speicheradresse in den Controller. Der Kontrollfluss ist invertiert: Nicht die App baut ihre Abhängigkeiten, das Framework "pusht" sie zur App.
LSP-Verstöße: Covariance & Contravariance
Das Liskovsche Substitutionsprinzip hat eine knochenharte Nebenbedingung für Parameter- und Rückgabetypen beim Überschreiben.
- Contravariance (Parameter): Die erbende Klasse darf die Methoden-Parameter lockern (generischer machen), aber niemals strikter machen. Wenn der Parent
Logge(Warning)erwartet, darf das ChildLogge(JedesLog)anbieten, aber nicht plötzlichLogge(NurCriticalWarning). - Covariance (Return): Die erbende Klasse darf als Rückgabewert spezifischer werden, aber niemals generischer. Parent retourniert
Fahrzeug-> Child darfAutoretournieren. Wenn diese Typen-Varianzen im API-Design gebrochen werden, stürzt das konsumierende Polymorphismus-Programm beim Laufzeit-Casting ab.
Die SRP-Schizophrenie (Wo zieht man die Grenze?)
Das Single Responsibility Principle ist das gefährlichste der fünf: "Eine Klasse sollte nur EINEN Grund haben, sich zu ändern."
Doch was ist ein "Grund"?
Wenn man SRP übertreibt (Schizophrenie), landet man bei Tausenden Klassen: UserCreator, UserEmailValidator, UserPasswordHasher, die jeweils exakt eine Zeile Code enthalten. Der Code ist maximal fragmentiert und man verliert völlig den Kontext der "Business Transaction".
Die Architekten-Faustregel lautet: "Gather together the things that change for the same reasons. Separate those things that change for different reasons." Cohesion (Zusammenhalt fachlich verwandter Konzepte) darf nicht durch blinden SRP-Dogmatismus zerstört werden.
Quick-Check
Interface Segregation?
Zwinge niemanden, Methoden zu implementieren, die er nicht braucht. "Arbeiter: arbeiten() und essen()". Ein Roboter kann arbeiten, aber nicht essen. Teile das Interface auf!Over-Engineering?
SOLID ist mächtig, aber verbos. Für kleine Scripts ("50 Zeilen") ist es Overkill. Nutze es für Enterprise-Systeme, die Jahre leben sollen.Widerspruch zu DRY?
Manchmal. SRP führt zu mehr Klassen (mehr Code), was auf den ersten Blick wie Redundanz aussieht. Aber es ist "gute" Trennung.