Prinzip der Einzelverantwortung
Die Definition des Einzelverantwortungsprinzips besagt, dass es für eine Klasse nur einen Grund für ihre Änderung geben sollte. Mit anderen Worten: Eine Klasse sollte nur für eine Sache verantwortlich sein. Wenn eine Klasse für zwei verschiedene Dinge verantwortlich ist, Methode M1 und Methode M2, müssen wir bei einer Änderung der M1-Methode die M1-Methode dieser Klasse ändern, aber zu diesem Zeitpunkt funktioniert die M2-Methode möglicherweise nicht. Dies ist nicht das, was wir erwartet haben, aber aufgrund dieses Designs ist es durchaus möglich. Daher müssen wir zu diesem Zeitpunkt die M1-Methode und die M2-Methode in zwei Klassen unterteilen. Lassen Sie jede Klasse sich nur auf ihre eigenen Methoden konzentrieren.
Die Vorteile des Einzelverantwortungsprinzips sind wie folgt:
Dadurch kann die Komplexität der Klasse verringert werden. Dies vereinfacht die Logik erheblich und verbessert die Lesbarkeit der Klasse und die Wartbarkeit des Systems, da es keine anderen seltsamen Methoden gibt, die unsere beeinträchtigen Verständnis der Bedeutung dieser Klasse. Wenn Änderungen auftreten, können die Auswirkungen der Änderungen minimiert werden, da Änderungen nur in dieser Klasse vorgenommen werden.
Öffnungs- und Schließprinzip
Das Offen-Geschlossen-Prinzip ist ebenso wie das Einzelverantwortungsprinzip ein sehr grundlegendes und allgemein vernünftiges Prinzip. Die Definition des Open-Closed-Prinzips besteht darin, dass Objekte (Klassen, Module, Funktionen usw.) in Software für Erweiterungen offen, für Änderungen jedoch geschlossen sein sollten.
Wenn sich die Anforderungen ändern, müssen wir den Code ändern. Zu diesem Zeitpunkt sollten wir versuchen, den ursprünglichen Code zu erweitern, anstatt ihn zu ändern, da dies zu weiteren Problemen führen kann.
Dieses Prinzip ist dasselbe wie das Prinzip der Einzelverantwortung. Es ist ein Prinzip, das jeder so denkt, aber nicht vorgibt, wie es zu tun ist.
Wir können das Öffnungs- und Schließprinzip auf eine Weise sicherstellen. Wir verwenden Abstraktion, um das Framework aufzubauen, und Implementierung, um die Details zu erweitern. Auf diese Weise verwenden wir bei einer Änderung direkt die Abstraktion, um eine konkrete Klasse zur Implementierung der Änderung abzuleiten.
Richter-Substitutionsprinzip
Das Liskov-Substitutionsprinzip ist ein sehr nützliches Konzept. Seine Definition
Wenn es für jedes Objekt o1 vom Typ T1 ein Objekt o2 vom Typ T2 gibt, sodass sich das Verhalten aller mit T1 definierten Programme P nicht ändert, wenn alle Objekte o1 durch o2 ersetzt werden, dann ist der Typ T2 ein Untertyp des Typs T1.
Es ist etwas kompliziert, das zu sagen, aber es gibt tatsächlich eine einfache Definition
Alle Verweise auf eine Basisklasse müssen in der Lage sein, Objekte ihrer Unterklassen transparent zu verwenden.
Laienhaft ausgedrückt lautet das Liskov-Substitutionsprinzip: Unterklassen können die Funktionen der übergeordneten Klasse erweitern, aber die ursprünglichen Funktionen der übergeordneten Klasse nicht ändern. Es enthält folgende Bedeutungen:
Unterklassen können abstrakte Methoden der übergeordneten Klasse implementieren, aber nicht abstrakte Methoden der übergeordneten Klasse nicht überschreiben.
Unterklassen können ihre eigenen einzigartigen Methoden hinzufügen.
Wenn eine Unterklassenmethode eine übergeordnete Klassenmethode überschreibt, sind die formalen Parameter der Methode lockerer als die Eingabeparameter der übergeordneten Klassenmethode.
Wenn eine Methode einer Unterklasse eine abstrakte Methode einer übergeordneten Klasse implementiert, ist der Rückgabewert der Methode strenger als der der übergeordneten Klasse.
Der Grund, warum das Liskov-Substitutionsprinzip dies erfordert, liegt darin, dass die Vererbung viele Mängel aufweist. Obwohl es sich um eine Methode zur Wiederverwendung von Code handelt, verstößt die Vererbung in gewissem Maße gegen die Kapselung. Die Attribute und Methoden der übergeordneten Klasse sind für die untergeordnete Klasse transparent, und die untergeordnete Klasse kann die Mitglieder der übergeordneten Klasse nach Belieben ändern. Dies führt auch dazu, dass andere Unterklassen nicht ordnungsgemäß funktionieren können, wenn sich die Anforderungen ändern und die Unterklasse einige Methoden der übergeordneten Klasse überschreibt. Daher wurde die Richter-Substitutionsregel vorgeschlagen.
Um sicherzustellen, dass das Programm dem Liskov-Substitutionsprinzip folgt, muss unser Programm Abstraktionen festlegen, Spezifikationen durch Abstraktion festlegen und dann die Implementierung verwenden, um die Details zu erweitern. Ja, das Liskov-Substitutionsprinzip und das Eröffnungs- und Schlussprinzip sind oft voneinander abhängig.
Prinzip der Abhängigkeitsumkehr
Das Abhängigkeitsinversionsprinzip bezieht sich auf eine spezielle Art der Entkopplung, sodass High-Level-Module nicht von den Implementierungsdetails von Low-Level-Modulen abhängen sollten und abhängige Module invertiert werden. Auch dies ist eine schwer zu verstehende Definition. Man kann sie einfach als
ausdrücken High-Level-Module sollten nicht von Low-Level-Modulen abhängen, beide sollten von ihren Abstraktionen abhängen. Details sollten von Abstraktionen abhängen In Java bezieht sich Abstraktion auf Schnittstellen oder abstrakte Klassen, von denen keine instanziiert werden kann. Die Details sind die Implementierungsklassen, bei denen es sich um Klassen handelt, die Schnittstellen implementieren oder abstrakte Klassen erben. Es kann instanziiert werden. Das High-Level-Modul bezieht sich auf das aufrufende Ende, und das Low-Level-Modul ist die spezifische Implementierungsklasse. In Java bedeutet das Abhängigkeitsinversionsprinzip, dass Abhängigkeiten zwischen Modulen durch Abstraktion entstehen. Es gibt keine direkte Abhängigkeit zwischen Implementierungsklassen und ihre Abhängigkeiten werden über Schnittstellen realisiert. Dies wird allgemein als schnittstellenorientierte Programmierung bezeichnet.
Wir haben unten ein Beispiel, um dieses Problem zu veranschaulichen. Dieses Beispiel zeigt einen Arbeiter, der einen Hammer benutzt, um etwas zu reparieren. Unser Code lautet wie folgt:
öffentliche Klasse Hammer {
public String function(){
return „Benutze einen Hammer, um Dinge zu reparieren“;
}
}
Arbeiter der öffentlichen Klasse {
Beseitigung öffentlicher Lücken (Hammerhammer){
System.out.println("worker" + hammer.function());
}
public static void main(String[] args) {
neuer Worker(). fix(new Hammer());
}
}
Dies ist ein sehr einfaches Beispiel, aber wenn wir eine neue Funktion hinzufügen möchten, verwenden Arbeiter Schraubenzieher, um Dinge zu reparieren. In dieser Klasse finden wir, dass dies schwierig ist. Weil unsere Worker-Klasse von einer bestimmten Hammer-Implementierungsklasse abhängt. Wir nutzen also die Idee der schnittstellenorientierten Programmierung und ändern sie in folgenden Code:
Tools für die öffentliche Schnittstelle {
public String function();
}
Dann ist unser Worker über diese Schnittstelle von anderen Detailklassen abhängig. Der Code lautet wie folgt:
Arbeiter der öffentlichen Klasse {
Behebung öffentlicher Lücken(Tools-Tool){
System.out.println("worker" + tool.function());
}
public static void main(String[] args) {
newWorker(). fix(new Hammer());
newWorker(). fix(neuer Schraubendreher());
}
}
Unsere Hammer- und Schraubendreher-Klasse implementieren diese Schnittstelle
öffentliche Klasse Hammer implementiert Tools{
öffentliche String-Funktion(){
return „Benutze einen Hammer, um Dinge zu reparieren“;
}
}
öffentliche Klasse Schraubendreher implementiert Werkzeuge{
@Override
öffentliche String-Funktion() {
return „Benutze einen Schraubenzieher, um etwas zu reparieren“;
}
}
Auf diese Weise weist unser Code durch schnittstellenorientierte Programmierung eine hohe Skalierbarkeit auf, reduziert die Kopplung zwischen Codes und verbessert die Stabilität des Systems.
Prinzip der Schnittstellenisolation
Die Definition des Schnittstellenisolationsprinzips lautet
Der Client sollte sich nicht auf Schnittstellen verlassen, die er nicht benötigt
Mit anderen Worten: Die Abhängigkeitsbeziehung zwischen Klassen sollte auf der kleinsten Schnittstelle hergestellt werden. Es scheint schwieriger zu verstehen. Lassen Sie uns dies anhand eines Beispiels veranschaulichen. Wir wissen, dass eine konkrete Klasse, wenn sie eine Schnittstelle in Java implementiert, alle Methoden in der Schnittstelle implementieren muss. Wenn wir eine Klasse A und eine Klasse B haben, die von Schnittstelle I abhängen, ist Klasse B die Implementierung der Abhängigkeit von Klasse A, und diese Schnittstelle I verfügt über 5 Methoden. Aber die Klassen A und B hängen nur von den Methoden 1, 2 und 3 ab, und die Klassen C und D hängen dann von der Schnittstelle I ab. Klasse D ist eine Implementierung der Abhängigkeit von Klasse C, aber sie hängen von den Methoden 1, 4 und 5 ab. Bei der Implementierung der Schnittstelle muss Klasse B dann die Methoden 4 und 5 implementieren, die sie nicht benötigt, und Klasse D muss die Methoden 2 und 3 implementieren, die sie nicht benötigt. Das ist einfach ein Desaster-Design.
Daher müssen wir die Schnittstelle aufteilen, dh die Schnittstelle in die kleinste Schnittstelle aufteilen, die die Abhängigkeiten der Klassen B und D erfüllt. Es ist nicht erforderlich, Schnittstellenmethoden zu implementieren, die nichts mit ihnen zu tun haben. In diesem Beispiel können wir die Schnittstelle beispielsweise in drei Teile aufteilen. Die erste Schnittstelle enthält nur Methode 1, die zweite Schnittstelle enthält die Methoden 2 und 3 und die dritte Schnittstelle enthält die Methoden 4 und 5. Auf diese Weise erfüllt unser Design das Prinzip der Schnittstellenisolation.
Die oben genannten Designideen können mit den Anfangsbuchstaben des Englischen zu SOLID geformt werden. Programme, die diese fünf Prinzipien erfüllen, gelten auch als SOLID-Kriterien.
Dimit-Prinzip
Das Dimit-Prinzip wird auch als Minimalwissensprinzip bezeichnet und seine Definition lautet
Ein Objekt sollte nur minimale Kenntnisse über andere Objekte behalten.
Denn je enger die Beziehung zwischen Klassen ist, desto größer ist der Grad der Kopplung. Daher ist dies auch das allgemeine Prinzip der Softwareprogrammierung, das wir befürworten: geringe Kopplung, hohe Kohäsion . Es gibt eine einfachere Definition des Demeter-Gesetzes
Kommunizieren Sie nur mit direkten Freunden. Lassen Sie uns zunächst erklären, was ein direkter Freund ist: Jedes Objekt hat eine Kopplungsbeziehung mit anderen Objekten. Solange zwischen zwei Objekten eine Kopplungsbeziehung besteht, sagen wir, dass die beiden Objekte Freunde sind. Es gibt viele Arten der Kopplung, z. B. Abhängigkeit, Assoziation, Kombination, Aggregation usw. Unter diesen nennen wir Klassen, die in Mitgliedsvariablen, Methodenparametern und Methodenrückgabewerten erscheinen, direkte Freunde, während Klassen, die in lokalen Variablen erscheinen, keine direkten Freunde sind. Mit anderen Worten: Es ist am besten, wenn unbekannte Klassen nicht als lokale Variablen innerhalb der Klasse erscheinen.
Hier können wir es anhand eines Beispiels aus der Praxis erklären. Wenn wir zum Beispiel eine CD brauchen, können wir zum Videoladen gehen und den Chef fragen, ob er die CD hat, die wir brauchen. Der Chef sagt, dass er die CD, die wir jetzt brauchen, nicht hat, und Sie können einfach vorbeikommen und sie holen es, wenn es verfügbar ist. Dabei ist es uns egal, wo oder wie der Chef die CD bekommen hat. Es ist uns egal, unter welchen Bedingungen der Chef die CD von seinem Freund bekommen hat. Wir sind mit ihm nicht einverstanden. Die Freunde (Fremde) des Chefs kommunizieren. Um es ganz klar auszudrücken: Es handelt sich um eine Zwischenmethode. Wir nutzen den Chef als Vermittler, um mit der Person in Kontakt zu treten, die die CD tatsächlich zur Verfügung stellt.
Das obige ist der detaillierte Inhalt vonWas sind die sechs Prinzipien des objektorientierten Designs in Java?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!