Ich bin gerade auf ein Muster gestoßen, das ich schon einmal gesehen habe, und wollte dazu Meinungen bekommen. Der betreffende Code beinhaltet eine Schnittstelle wie folgt:
%Vor%Und die erwartete Verwendung ist wie folgt:
%Vor%Dafür gibt es Gründe. Die setText (...) und getOccurances (...) sind da, weil es nach der gleichen teuren Analyse der Daten mehrere Abfragen geben kann, die aber zu einer Ergebnisklasse refaktoriert werden können.
Warum ich denke, das ist so schlecht: Die Implementierung speichert den Zustand in einer Weise, die von der Schnittstelle nicht klar angezeigt wird. Ich habe auch etwas Ähnliches gesehen, das eine Schnittstelle betrifft, die "prepareResult" und dann "getResult" aufrufen muss. Jetzt kann ich an gut entworfenen Code denken, der einige dieser Eigenschaften einsetzt. Die Hadoop Mapper-Oberfläche erweitert JobConfigurable und Closeable, aber ich sehe einen großen Unterschied, weil es ein Framework ist, das Benutzercode verwendet, der diese Schnittstellen implementiert, im Gegensatz zu einem Service, der mehrere Implementierungen haben kann. Ich nehme an, dass alles, was mit der Aufnahme einer "nahen" Methode zu tun hat, die aufgerufen werden muss, gerechtfertigt ist, da es keinen anderen vernünftigen Weg gibt, dies zu tun. In einigen Fällen, wie JDBC, ist dies eine Konsequenz einer undichten Abstraktion, aber in den beiden Code-Stücken, an die ich denke, ist es ziemlich klar, dass Programmierer hastig eine Schnittstelle zu einer Spaghetti-Code-Klasse hinzufügen, um sie zu bereinigen.
Meine Fragen sind:
Wenn das üblich genug ist, um einen Namen zu verdienen, empfehle ich das "Secret Handshake" Anti-Pattern für eine Schnittstelle, die Sie dazu zwingt, mehrere Methoden in einer bestimmten Reihenfolge aufzurufen, wenn die Schnittstelle nicht von Natur aus stateful ist (wie eine Collection) .
Ja, es ist ein Anti-Pattern: Sequentielle Kopplung .
Ich würde in Options
umgestalten - an die Factory übergeben und Results
von einer analyseText()
Methode zurückgegeben.
Ich bin mir nicht sicher, ob es ein beschriebenes Anti-Pattern ist, aber ich stimme völlig zu, dass dies eine schlecht gestaltete Oberfläche ist. Es lässt zu viele Möglichkeiten für Fehler und verletzt mindestens ein Schlüsselprinzip: Machen Sie Ihre API schwer zu missbrauchen.
Neben Missbrauch kann diese API auch zu schwer zu debuggenden Fehlern führen, wenn mehrere Threads dieselbe Instanz verwenden.
Joshua Bloch hat tatsächlich eine ausgezeichnete Präsentation (36m16s und 40m30s) über API-Design und er spricht dies als eine der Eigenschaften einer schlecht gestalteten API.
Ich kann hier nichts Schlechtes sehen. setText()
bereitet die Bühne vor; Danach haben Sie einen oder mehrere Aufrufe von getOccurances()
. Da setText()
so teuer ist, kann ich mir keinen anderen Weg vorstellen.
getOccurances(text, query)
würde den "geheimen Handshake" zu enormen Performance-Kosten beheben. Sie könnten versuchen, Text in getOccurances()
zwischenzuspeichern und nur Ihre internen Caches zu aktualisieren, wenn sich der Text ändert, aber das sieht mehr und mehr nach einem OO-Prinzip aus. Wenn eine Regel keinen Sinn ergibt, wenden Sie sie nicht an. Softwareentwickler haben ein Gehirn aus einem Grund.
Eine mögliche Lösung - Fluent chaning verwenden. Das vermeidet eine Klasse, die Methoden enthält, die in einer bestimmten Reihenfolge aufgerufen werden müssen. Es ähnelt stark dem Builder-Muster, das dafür sorgt, dass Sie keine Objekte lesen, die sich noch in der Mitte befinden.
Tags und Links java anti-patterns