In den meisten Java-Codes werden Java-Objekte folgendermaßen deklariert:
Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();
Anstatt von:
HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();
Warum wird das Java-Objekt vorzugsweise über die Schnittstelle definiert, anstatt über die Implementierung, die tatsächlich verwendet wird?
Antworten:
Der Grund dafür ist, dass die Implementierung dieser Schnittstellen in der Regel nicht relevant ist, wenn Sie den Anrufer dazu verpflichten, eine zu übergeben
HashMap
an eine Methode zu übergeben, müssen Sie im Wesentlichen festlegen, welche Implementierung verwendet werden soll. In der Regel sollten Sie sich also eher um die Benutzeroberfläche als um die eigentliche Implementierung kümmern und den Schmerz und das Leid vermeiden, die dazu führen können, dass Sie alle Methodensignaturen ändern müssen,HashMap
wenn Sie entscheiden, dass Sie sieLinkedHashMap
stattdessen verwenden möchten.Es sollte gesagt werden, dass es Ausnahmen gibt, wenn die Implementierung relevant ist. Wenn Sie eine Karte benötigen, wenn die Reihenfolge wichtig ist, können Sie verlangen, dass ein
TreeMap
oder einLinkedHashMap
übergeben wird, oder noch besserSortedMap
, dass keine bestimmte Implementierung angegeben wird. Dies verpflichtet den Aufrufer, zwangsläufig eine bestimmte Art der Implementierung von Map zu bestehen und weist nachdrücklich auf diese Reihenfolge hin ist wichtig. Das heißt, könnten SieSortedMap
eine unsortierte überschreiben und übergeben? Ja, natürlich, aber erwarten Sie, dass daraus schlimme Dinge werden.Die beste Praxis schreibt jedoch vor, dass Sie keine spezifischen Implementierungen verwenden sollten, wenn dies nicht wichtig ist. Dies gilt im Allgemeinen. Wenn Sie es zu tun
Dog
undCat
welche ergeben sich ausAnimal
, um einen optimalen Einsatz der Vererbung zu machen, sollten Sie in der Regel vermeiden Methoden spezifisch mitDog
oderCat
. Eher alle Methoden inDog
oderCat
sollten Methoden in überschreibenAnimal
und es erspart Ihnen auf lange Sicht Ärger.quelle
SortedMap
nicht so seinTreeMap
.SortedMap
ist eine von mehreren Implementierungen, die sich mit der Bestellung befassen. Darum geht es nicht.TreeMap
bestellt auch Elemente entsprechend der Implementierung des SchlüsselsComparable
oder einer gegebenenComparator
Schnittstelle.LinkedHashMap
implementiert a nichtSortedMap
. Die einzigen Unterklassen vonSortedMap
sindConcurrentSkipListMap
undTreeMap
.In Laymans Worten:
Aus dem gleichen Grund bauten die Hersteller von Elektrogeräten ihre Produkte mit elektrischen Steckern, anstatt einfach die Kabel abzuziehen, und die Häuser sind mit Wandsteckdosen ausgestattet, anstatt Kabel, die aus der Wand herausragen, abzuziehen.
Indem Sie stattdessen Standardstecker verwenden, können Sie die gleichen Geräte an jeden kompatiblen Stecker im ganzen Haus anschließen.
Aus Sicht der Steckdose spielt es keine Rolle, ob Sie ein Fernsehgerät oder eine Stereoanlage anschließen.
Das macht sowohl das Gerät als auch die Steckdose nützlicher.
Nehmen Sie zum Beispiel eine Methode, die eine Map als Argument akzeptiert.
Die Methode funktioniert unabhängig davon, ob Sie eine HashMap oder eine LinkedHashMap übergeben, sofern es sich um eine Unterklasse von Map handelt.
Das ist das Liskov-Substitutionsprinzip .
In dem von Ihnen angegebenen Beispielcode bedeutet dies, dass Sie später aus irgendeinem Grund die konkrete Implementierung von Hash ändern können und den Rest des Codes nicht mehr ändern müssen.
Das Problem mit der Software ist, dass die Leute, da es relativ einfach ist, Dinge später ohne Verschwendung von Ziegeln oder Mörtel zu ändern, davon ausgehen, dass sich diese Art des Vorausdenkens nicht lohnt. Die Realität hat uns jedoch gezeigt, dass die Softwarewartung sehr teuer ist.
quelle
Es muss dem Prinzip der Schnittstellentrennung (das 'I' in SOLID) folgen ). Dadurch wird verhindert, dass Code, der diese Objekte verwendet, von den Methoden der Objekte abhängt, die er nicht benötigt, wodurch der Code weniger gekoppelt und daher einfacher zu ändern ist.
Wenn Sie zum Beispiel später herausfinden, dass Sie wirklich eine benötigen
LinkedHashMap
, können Sie diese Änderung sicher vornehmen, ohne dass sich dies auf einen anderen Code auswirkt.Es gibt jedoch einen Kompromiss, da Sie den Code, der Ihr Objekt als Parameter verwenden kann, künstlich einschränken. Angenommen, es gibt eine Funktion, für die aus irgendeinem Grund eine erforderlich ist
HashMap
. Wenn Sie a zurückgebenMap
, können Sie Ihr Objekt nicht an diese Funktion übergeben. Sie müssen die Wahrscheinlichkeit abwägen, dass Sie irgendwann in der Zukunft die zusätzliche Funktionalität benötigen, die in der konkreteren Klasse liegt, mit dem Wunsch, die Kopplung zu begrenzen und Ihre öffentliche Schnittstelle so klein wie möglich zu halten.quelle
Wenn die Variable auf eine Schnittstelle beschränkt ist, wird sichergestellt, dass keine der Verwendungen dieser Variablen
HashMap
bestimmte Funktionen verwendet, die möglicherweise nicht auf der Schnittstelle vorhanden sind. Daher kann die Instanz später ohne Bedenken in eine andere Implementierung geändert werden, solange die neue Instanz auch die implementiert Schnittstelle.Aus diesem Grund ist es immer empfehlenswert, Ihre Variablen als Schnittstelle zu deklarieren, wenn Sie eine Objektschnittstelle verwenden möchten, und nicht die jeweilige Implementierung. Dies gilt für alle Arten von Objekten, die Sie möglicherweise verwenden und die über eine Schnittstelle verfügen. Der Grund, warum Sie es oft sehen, ist, dass viele Menschen dies als Gewohnheit eingebaut haben.
Das heißt, es ist nicht schädlich, manchmal keine Schnittstellen mehr zu verwenden, und die meisten von uns befolgen diese Regel nicht immer ohne wirklichen Schaden. Es ist nur eine gute Praxis, sich an die Regeln zu halten, wenn Sie das Gefühl haben, dass der Code möglicherweise geändert wird und in Zukunft Wartung / Wachstum benötigt. Es ist weniger bedenklich, wenn Sie Code hacken, von dem Sie nicht vermuten, dass er eine lange Lebensdauer hat oder von großer Bedeutung ist. Ein Verstoß gegen diese Regel hat in der Regel eine kleine Konsequenz: Wenn Sie die Implementierung auf eine andere umstellen, müssen Sie sie möglicherweise etwas umgestalten. Wenn Sie sich also nicht immer daran halten, werden Sie sich nicht sehr verletzen .
quelle