Bei einem kürzlich durchgeführten Vorstellungsgespräch konnte ich keine Frage zu SOLID beantworten - über die grundlegende Bedeutung der verschiedenen Prinzipien hinaus. Es nervt mich wirklich. Ich habe ein paar Tage lang herumgegraben und muss noch eine zufriedenstellende Zusammenfassung finden.
Die Interviewfrage lautete:
Wenn Sie sich ein .Net-Projekt ansehen würden, von dem ich Ihnen sagte, dass es die SOLID-Prinzipien strikt befolgt, was würden Sie in Bezug auf das Projekt und die Codestruktur erwarten?
Ich zappelte ein bisschen herum, beantwortete die Frage nicht wirklich und bombardierte dann.
Wie hätte ich besser mit dieser Frage umgehen können?
Antworten:
S = Prinzip der Einzelverantwortung
Ich würde also eine gut organisierte Ordner- / Dateistruktur und Objekthierarchie erwarten. Jede Klasse / Funktion sollte so benannt werden, dass ihre Funktionalität sehr offensichtlich ist, und sie sollte nur Logik enthalten, um diese Aufgabe auszuführen.
Wenn Sie riesige Managerklassen mit Tausenden von Codezeilen sehen würden, wäre dies ein Zeichen dafür, dass eine einzelne Verantwortung nicht befolgt wird.
O = offenes / geschlossenes Prinzip
Dies ist im Grunde die Idee, dass neue Funktionen durch neue Klassen hinzugefügt werden sollten, die nur minimale Auswirkungen auf vorhandene Funktionen haben oder deren Änderung erforderlich ist.
Ich würde erwarten, dass Objektvererbung, Untertypisierung, Schnittstellen und abstrakte Klassen in großem Umfang zum Einsatz kommen, um das Design eines Teils der Funktionalität von der tatsächlichen Implementierung zu trennen und anderen zu ermöglichen, nebenbei andere Versionen zu implementieren, ohne die zu beeinträchtigen Original.
L = Liskov-Substitutionsprinzip
Dies hat mit der Möglichkeit zu tun, Untertypen als übergeordnete Typen zu behandeln. Dies ist in C # ein Kinderspiel, wenn Sie eine ordnungsgemäße Hierarchie geerbter Objekte implementieren.
Ich würde erwarten, dass Code allgemeine Objekte als Basistyp behandelt und Methoden für die Basis- / Abstraktionsklassen aufruft, anstatt die Untertypen selbst zu instanziieren und zu bearbeiten.
I = Prinzip der Grenzflächentrennung
Dies ist ähnlich wie bei SRP. Grundsätzlich definieren Sie kleinere Teilmengen von Funktionalität als Schnittstellen und mit denen arbeiten , um Ihr System zu halten entkoppelt (zB
FileManager
könnten die einzelnen responsibilty Umgang mit Datei - I / O, aber das könnte ein implementierenIFileReader
undIFileWriter
die enthaltenen spezifischen Methodendefinitionen für das Lesen und Schreiben von Dateien).D = Abhängigkeitsumkehrprinzip.
Auch hier geht es darum, ein System entkoppelt zu halten. Vielleicht möchten Sie eine .NET Dependency Injection-Bibliothek verwenden, die in der Lösung wie
Unity
oderNinject
oder in einem ServiceLocator-System wie verwendet wirdAutoFacServiceLocator
.quelle
Überall gibt es viele kleine Klassen und Schnittstellen mit Abhängigkeitsinjektion. Wahrscheinlich würden Sie in einem großen Projekt auch ein IoC-Framework verwenden, um die Lebensdauer all dieser kleinen Objekte zu konstruieren und zu verwalten. Siehe https://stackoverflow.com/questions/21288/which-net-dependency-injection-frameworks-are-worth-looking-into
Beachten Sie, dass ein großes .NET-Projekt, das STRIKT SOLID-Prinzipien folgt, nicht unbedingt eine gute Codebasis für jedermann bedeutet. Je nachdem, wer der Interviewer war, wollte er / sie, dass Sie zeigen, dass Sie verstehen, was SOLID bedeutet, und / oder überprüfen, wie dogmatisch Sie die Gestaltungsprinzipien befolgen.
Sie sehen, um SOLID zu sein, müssen Sie folgen:
S ingle Verantwortung Prinzip, so dass Sie nur viele kleine Klassen jeder von ihnen eine Sache tut haben
O Pen-Closed-Prinzip, das in .NET normalerweise mit Abhängigkeitsinjektion implementiert wird, was auch das I und das D unten erfordert ...
Das L iskov-Substitutionsprinzip lässt sich wahrscheinlich nicht mit einem Einzeiler in c # erklären. Zum Glück gibt es andere Fragen , die es Adressierung, zB https://stackoverflow.com/questions/4428725/can-you-explain-liskov-substitution-principle-with-a-good-c-sharp-example
I nterface Segregations Prinzip arbeitet zusammen mit dem Open-Closed - Prinzip. Wenn man es wörtlich befolgt, würde es bedeuten, eine große Anzahl sehr kleiner Schnittstellen zu bevorzugen, anstatt nur wenige "große" Schnittstellen
Prinzip der D- Ependenz-Inversion Klassen auf hoher Ebene sollten nicht von Klassen auf niedriger Ebene abhängen, beide sollten von Abstraktionen abhängen.
quelle
Einige grundlegende Dinge, die ich in der Codebasis eines Shops erwarten würde, der SOLID in seiner täglichen Arbeit unterstützt:
Viele Adapter- und Composite-Muster - Ich würde die Verwendung vieler Adapter-Muster (eine Klasse, die eine Schnittstelle implementiert, indem sie die Funktionalität einer anderen Schnittstelle "durchläuft") erwarten, um das Einstecken einer für einen Zweck entwickelten Abhängigkeit in geringfügig zu rationalisieren verschiedene Orte, an denen auch seine Funktionalität benötigt wird. Aktualisierungen, die so einfach wie das Ersetzen eines Konsolenprotokollierers durch einen Dateiprotokollierer sind, verstoßen gegen LSP / ISP / DIP, wenn die Schnittstelle aktualisiert wird, um ein Mittel zum Angeben des zu verwendenden Dateinamens bereitzustellen. Stattdessen macht die Dateiprotokollierungsklasse die zusätzlichen Member verfügbar, und ein Adapter lässt die Dateiprotokollierung wie eine Konsolenprotokollierung aussehen, indem er die neuen Elemente verbirgt. Nur das Objekt, das all dies zusammenfasst, muss den Unterschied kennen.
Wenn eine Klasse eine Abhängigkeit einer ähnlichen Schnittstelle zu einer vorhandenen hinzufügen muss, um das Ändern des Objekts (OCP) zu vermeiden, besteht die übliche Antwort darin, ein zusammengesetztes / strategisches Muster (eine Klasse, die die Abhängigkeitsschnittstelle implementiert und mehrere andere verwendet) zu implementieren Implementierungen dieser Schnittstelle mit unterschiedlich viel Logik, die es der Klasse ermöglichen, einen Aufruf an eine, einige oder alle Implementierungen weiterzuleiten).
quelle
Lenken Sie sie mit Jon Skeets Diskussion darüber ab, wie das 'O' in SOLID "nicht hilfreich und schlecht verstanden" ist, und bringen Sie sie dazu, über Alistair Cockburns "geschützte Variante" und Josh Blochs "Erbschaftsentwurf" zu sprechen oder es zu verbieten.
Kurze Zusammenfassung von Skeets Artikel (obwohl ich nicht empfehlen würde, seinen Namen zu streichen, ohne den ursprünglichen Blog-Beitrag zu lesen!):
Das OP fragte: "Wie hätte ich besser mit dieser Frage umgehen können?" Als leitender Ingenieur, der ein Interview führt, wäre ich unermesslich mehr an einem Kandidaten interessiert, der intelligent über die Vor- und Nachteile verschiedener Code-Design-Stile sprechen kann, als an jemandem, der eine Liste von Stichpunkten auf den Kopf stellt.
Eine weitere gute Antwort wäre: "Nun, das hängt davon ab, wie gut sie es verstanden haben. Wenn sie nur die SOLID-Schlagworte kennen, würde ich mit Missbrauch der Vererbung, übermäßigem Einsatz von Frameworks zur Abhängigkeitsinjektion und einer Million kleiner Schnittstellen rechnen, von denen keine spiegeln das Domain-Vokabular wider, das für die Kommunikation mit dem Produktmanagement verwendet wird ... "
quelle
Es gibt wahrscheinlich eine Reihe von Möglichkeiten, wie dies mit unterschiedlichem Zeitaufwand beantwortet werden kann. Ich denke jedoch, dass dies eher im Sinne von "Wissen Sie, was SOLID bedeutet?" Die Beantwortung dieser Frage läuft also wahrscheinlich darauf hinaus, die Punkte zu treffen und sie anhand eines Projekts zu erklären.
Sie erwarten also Folgendes:
quelle
Dies ist eine ausgezeichnete Frage, obwohl ich denke, dass es eine schwierige Interviewfrage ist.
SOLID-Prinzipien bestimmen Klassen und Interfaces und wie sie sich zueinander verhalten.
Diese Frage hat mehr mit Dateien und nicht unbedingt mit Klassen zu tun .
Eine kurze Beobachtung oder Antwort, die ich geben möchte, ist, dass Sie im Allgemeinen Dateien sehen, die nur eine Schnittstelle enthalten, und häufig ist die Konvention, dass sie mit einem Groß-I beginnen. Darüber hinaus würde ich erwähnen, dass die Dateien keinen doppelten Code (insbesondere innerhalb eines Moduls, einer Anwendung oder einer Bibliothek) haben und dass der Code über bestimmte Grenzen zwischen Modulen, Anwendungen oder Bibliotheken hinweg sorgfältig geteilt wird.
Robert Martin erörtert dieses Thema im Bereich C ++ unter Entwerfen objektorientierter C ++ - Anwendungen mit der Booch-Methode (siehe Abschnitte zu Kohäsion, Closure und Wiederverwendbarkeit) und in Clean Code .
quelle