Ich bin gerade auf ein Muster gestoßen, das ich vorher gesehen habe, und wollte Meinungen dazu bekommen. Der betreffende Code beinhaltet eine Schnittstelle wie folgt aus:Secret Handshake Anti-Pattern
public interface MyCrazyAnalyzer {
public void setOptions(AnalyzerOptions options);
public void setText(String text);
public void initialize();
public int getOccurances(String query);
}
Und die erwartete Nutzung ist wie folgt:
MyCrazyAnalyzer crazy = AnalyzerFactory.getAnalyzer();
crazy.setOptions(true);
crazy.initialize();
Map<String, Integer> results = new HashMap<String, Integer>();
for(String item : items) {
crazy.setText(item);
results.put(item, crazy.getOccurances);
}
ist es Gründe für einen Teil davon. Die setText (...) und getOccurances (...) sind da, weil es mehrere Abfragen gibt, die Sie nach der gleichen teuren Analyse der Daten durchführen möchten, aber dies kann zu einer Ergebnisklasse refaktoriert werden.
Warum ich denke, das ist so schlecht: Die Implementierung speichert Zustand in einer Weise, die nicht eindeutig von der Schnittstelle 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-Schnittstelle 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:
- Hat jeder zustimmen, dass dieses eine schlecht gestaltete Oberfläche ist?
- Ist dies ein beschriebenes Anti-Pattern?
- Gehört diese Art von Initialisierung jemals in eine Schnittstelle?
- Scheint das nur falsch für mich, weil ich eine Präferenz für funktionellen Stil und Unveränderlichkeit habe?
Wenn dies häufig genug ist, einen Namen zu verdienen, schlage ich vor, das „Secret Handshake“ anti-Muster für eine Schnittstelle, die Sie zwingt mehrere Methoden in einer bestimmten Reihenfolge zu nennen, wenn die Schnittstelle nicht von Natur aus Stateful ist (wie eine Sammlung).
Um ehrlich zu sein, erinnert mich dieses "Muster" an DataReaders in ADO.NET. Das bedeutet nicht, dass es notwendigerweise eine gute Idee ist, aber es wird sogar in ernsthaften APIs verwendet. –
Gutes Anti-Muster. Wenn Objekte so initialisiert werden sollten, könnten wir Konstruktoren in Interfaces angeben. Ich mag auch den Begriff "geheimer Händedruck". – CurtainDog
Zumindest ist es explizit schlecht, im Gegensatz zu java.util.MessageFormat, die temporären internen Zustand während einzelner Methodenaufrufe verwendet. –