Schauen wir uns das praktisch an
Obj 3
Jetzt weiß, Obj 4
existiert. Na und? Warum kümmern wir uns?
DIP sagt
"High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beide sollten von Abstraktionen abhängen."
OK, aber sind nicht alle Objekte Abstraktionen?
DIP sagt auch
"Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen."
OK, aber wenn mein Objekt richtig gekapselt ist, verbirgt das keine Details?
Manche Leute bestehen blind darauf, dass jedes Objekt eine Schlüsselwortschnittstelle benötigt. Ich bin keiner von ihnen. Ich möchte blind darauf bestehen, dass, wenn Sie sie jetzt nicht verwenden, Sie einen Plan brauchen, um damit umzugehen, dass Sie später so etwas brauchen.
Wenn Ihr Code in jeder Version vollständig überarbeitet werden kann, können Sie Schnittstellen später bei Bedarf extrahieren. Wenn Sie Code veröffentlicht haben, den Sie nicht neu kompilieren möchten, und sich wünschen, Sie hätten über eine Benutzeroberfläche gesprochen, benötigen Sie einen Plan.
Obj 3
weiß Obj 4
existiert. Aber weiß Obj 3
, ob Obj 4
es konkret ist?
Genau deshalb ist es so schön, sich NICHT new
überall zu verbreiten . Wenn Sie Obj 3
nicht wissen, ob Obj 4
es konkret ist, wahrscheinlich, weil es es nicht erstellt hat, dann ist es Ihnen egal, wenn Sie sich später einschleichen und sich Obj 4
in eine abstrakte Klasse verwandeln Obj 3
.
Wenn du das schaffst, Obj 4
war es die ganze Zeit über völlig abstrakt. Das einzige, was Sie tun können, wenn Sie von Anfang an eine Schnittstelle zwischen ihnen herstellen, ist die Gewissheit, dass niemand versehentlich Code hinzufügt, der verrät, dass dies Obj 4
gerade konkret ist. Geschützte Konstruktoren können dieses Risiko mindern, aber das führt zu einer anderen Frage:
Befinden sich Obj 3 und Obj 4 im selben Paket?
Objekte werden häufig auf irgendeine Weise gruppiert (Paket, Namespace usw.). Wenn sie sinnvoll gruppiert werden, ändern sich eher die Auswirkungen innerhalb einer Gruppe als zwischen Gruppen.
Ich mag es, nach Merkmalen zu gruppieren. Wenn Obj 3
und Obj 4
in der gleichen Gruppe und Schicht ist , ist es sehr unwahrscheinlich , dass Sie eine veröffentlicht werden und nicht wollen , dass es Refactoring während benötigen nur die andere zu ändern. Das heißt, es ist weniger wahrscheinlich, dass diese Objekte von einer Abstraktion profitieren, bevor ein eindeutiger Bedarf besteht.
Wenn Sie jedoch eine Gruppengrenze überschreiten, ist es eine gute Idee, Objekte auf beiden Seiten unabhängig voneinander variieren zu lassen.
Es sollte so einfach sein, aber leider haben sowohl Java als auch C # unglückliche Entscheidungen getroffen, die dies erschweren.
In C # ist es Tradition, jede Schlüsselwortschnittstelle mit einem I
Präfix zu benennen . Das zwingt die Kunden zu WISSEN, dass sie mit einer Schlüsselwortschnittstelle sprechen. Das steht im Widerspruch zum Refactoring-Plan.
In Java ist es Tradition, ein besseres Benennungsmuster zu verwenden: FooImple implements Foo
Dies hilft jedoch nur auf Quellcodeebene, da Java Schlüsselwortschnittstellen in eine andere Binärdatei kompiliert. Das bedeutet, dass beim Refactoring Foo
von konkreten zu abstrakten Clients, bei denen kein einziges Zeichen des Codes geändert werden muss, noch eine Neukompilierung erforderlich ist.
Es sind diese BUGS in diesen bestimmten Sprachen, die die Menschen davon abhalten, formelle Abstracts zu erstellen, bis sie sie wirklich brauchen. Sie haben nicht gesagt, welche Sprache Sie verwenden, aber Sie verstehen, dass es einige Sprachen gibt, die diese Probleme einfach nicht haben.
Sie haben nicht angegeben, welche Sprache Sie verwenden. Ich fordere Sie daher dringend auf, Ihre Sprache und Situation sorgfältig zu analysieren, bevor Sie entscheiden, dass es sich überall um Keyword-Schnittstellen handelt.
Dabei spielt das YAGNI-Prinzip eine zentrale Rolle. Aber auch "Bitte mach es mir schwer, in den Fuß zu schießen".