Ok, sorry, dass ich das nicht direkt verstanden hatte. Jetzt verstehe ich Deinen Punkt.
Im Folgenden einmal eine Erläuterung meiner Sichtweise.
Hier beissen sich zwei Forderungen:
a) Dependency Inversion Principle
Dahinter versteckt sich., dass (High Level) Klassen nicht von (Low Level) Klassen abhängig sein sollten sondern von Interfaces und dass Interfaces nicht von Details abhängig sein sollten sondern Details von Interfaces.
b) Ich sehe aber auch immer YAGNI (You aint gonna need it)
Wenn man die typischen Business Applikationen erstellt mit der typischen Datenbank mit Entitities und darauf aufbaen dann ein Business Logic Layer und darauf dann irgendwelche Controller / UIs, dann finden sich immer wieder typische Fälle, wo klar ist: Hier braucht man keine Interfaces:
- Entities haben in der Regel keine Interfaces. Ich habe zumindest noch zu der Klasse Empolyee kein Employee Interface gesehen oder so. (Hier auch wichtig: Die Anforderung zu einem Interface kommt aus meiner Sicht immer von denen, die etwas nutzen wollen! Dazu später noch einmal mehr!)
- Dinge auf oberster Ebene - die werden nicht genutzt - daher auch keine Interfaces. Also der EmployeeController des Rest Service. Da habe ich noch nie ein Interface gesehen und das macht auch keinen Sinn.
Nun wie versprochen meine Sicht auf diese DIP und zu den Interfaces. Wann und wie erstelle ich diese?
Generell erstelle ich nie pauschal irgendwelche Interfaces. YAGNI! So lange ich nicht weiss, ob ich die überhaupt brauche, wird da nichts erstellt!
So schreibe ich also z.B. eine Klasse Dog. Es gibt kein DogInterface (Und wird es so eigentlich auch nie geben). Es gibt keinen Grund, das konkrete Interface, das Dog bietet, komplett auch in ein Interface zu schreiben.
Die Interfaces kommen nur über die Nutzer der Klasse:
- Eine Nutzung von Dog ist, dass er gefüttert (feed) werden kann. Jemand, der einen Hund füttern kann, will aber nicht abhängig sein von der konkreten Implementierung. Daher braucht man hier nun ein Interface. Aber was für ein Interface? Ein DogInterface? Das wohl kaum, denn es wrd ja nur das feed() benötigt. Also gibt es ein Interface Feedable oder so.
- Der Hund soll bellen (bark) können. Also bauchen wir hier auch ein entsprechendes Interface. Aber wieder speziell für diesen Sachverhalt. Die Alarmanlage, die dann den Hund bellen lässt, hat mit dem Füttern ja nichts am Hut. Und statt einem reellen Hund steckt da vermutlich meist auch eine Elektronik dahinter, die dann "bellt". Also wirklich nichts mit DogInterface oder so.
...
Natürlich kann es Fälle geben, wo Interface und Implementierung überein stimmen. Dann ist das Map Interface auch genau das, was man in der HashMap implementiert.
Und in einem Punkt hast du Recht: Es kann durchaus Sinn machen, das Beispiel von mir auf zu dröseln:
- Translator wird ein reines Interface
- Die Implementierung wird zu MapTranslator
- Du kannst dann Deine Implementierung als ArrayTranslator hinzu fügen oder so
Sowas gibt es bei formalistischen Entwicklungen durchaus. Dann werden Regeln gerne so angewendet. Da gibt es dann einen Architekten oder Prof, der einem dummen Programmierer oder Studenten sagt, wie es sein muss. Weil er es so meint und das ohne wirklichen Grund (Es ist eine einfache Formalie.)
YAGNI ist daher sehr wichtig. Nehmen wir wieder das Beispiel:
- Ich habe da jetzt diese Implementierung. Jetzt kommt - entgegen allen Erwartungen - diese neue Implementation. Ich kann es relativ einfach umstellen. Das Interface bekommen 1:1 genu das, was die Klasse hat. Es ist halt eine triviale Klasse. Die Abstraktion ist also einfach. Die Klasse selbst wurde nur umbenannt und implementiert das Interface nun. Damit sind wir aber schon fertig.
Was wir nun noch ändern müssen, sind die Stellen, an denen Instanzen erzeugt werden. Das ist eine typische Sache: Das wenn möglich zentralisieren. DIP schlägt dazu z.B. Praktiken vor (z.B. bei clean-code-developer.de):
- Konstruktorparameter
- Inversion of Control Container
- Dependency LookupDie notwendigen Anpassungen an den Abhängigkeiten fallen also nicht wirklich wild aus.
Daher ist aus meiner Sicht immer der gesunde Menschenverstand gefragt: Braucht man das, was ich da schreibe, denn überhaupt?
Dazu ist meine Meinung halt ganz klar: Code Smell. Eine private Methode zeigt, dass Deine Klasse in Verhalten hat (Methoden machen ja irgendwas und daher ist es ein Verhalten), das schlicht kein Verhalten Deiner Klasse ist (Weil das Verhalten ja eigentlich durch die von außen aufrufbare Methoden bestimmt wird).
Daher ist die Frage immer: Was für eine provate Methode hast Du da? Ist da ggf. ein Refactoring angebracht und dieses Verhalten kommt in eine eigene Klasse? Dann hast Du eine Klasse, von der Du Instanzen anlegen kannst und die Du einfach testen können solltest. Die Instanz selbst ist aber natürlich in der ursprünglichen Klasse gekapselt. Oft ist dies bereits die naheliegende Lösung.
Generell sind dies aber auch Dinge, die nur passieren können, wenn man einfach so entwickelt und Tests dann später macht. Bei Test Driven Development würde man in diese Situation nie kommen meine ich.
Ist es evtl. eine Idee, rein zu Übungszwecken mal etwas TDD auszuprobieren? Kent Becks "Test Driven Development: By Example" Buch wäre da mein Tipp. (Ich kaufe ja gerne Bücher - ich habe mir da einen monatliches Etat eingeräumt, das ich dann nutze. Ich finde es nicht gut, dass man
einfach so bei Google nach einem PDF eines Buches suchen kann und dann das Werk von irgend wem eingescannt findet, da die Autoren ja davon leben wollen und müssen und ich will ja immer neue, aktualisierte Bücher möchte ...)
Das ist kein Aufruf a.la. "Du musst TDD praktizieren". Es ist aber eine einfache Übung, so wie es viele Übungen gibt. Und man schreibt dann testbare Methoden. Und wenn man dann ohne Tests Code schreibt, dann hat man ein gewisses Wissen, wie diese testbaren Klassen denn aussahen und richtet sich etwas danach. Optional kann man sich auch gewisse Praktiken anschauen / identifizieren. Da habe ich aber keine passenden Links / Bücher zur Hand.
Noch einmal: Das ist meine pers. Sicht. Das ist etwas, das ich in der Praxis durchaus erlebt habe und was dort so auch gewollt ist oder akzeptiert wurde. Das muss so nicht sein. Es gibt garantiert gegensätzliche Meinungen (z.B. bei eurem Prof

) und da muss man sich immer überlegen, was man macht. Im Dunstkreis des Profs wird die Entscheidung leicht fallen, da man von ihm Punkte bekommt. In einem Projekt ist es ebenso einfach - da erfüllt man die Anforderungen so gut es geht und wenn die Anforderung ist, dass alles ein Interface und ein Controller bekommt und man alle 2 Stunden gen Grady Booch beeten muss: Was macht man nicht alles für seinen Stundenlohn....