Ich habe eine unerwartete Situation in einem Projekt, in dem alle Typen, die eine Klasse erweitern, in eine Java-Sammlung gepackt werden. Aber nur eine bestimmte Erweiterung dieser Klasse enthält eine zusätzliche Methode. Nennen wir es "also ()"; und lassen Sie mich klar sein, dass keine andere Erweiterung es hat. Kurz bevor ich eine Aufgabe für jedes Element in dieser Sammlung ausführe, muss ich auch () für jedes Element aufrufen, das es implementiert.
Der einfachste Weg ist folgender:
stuff.stream().filter(item -> item instanceof SpecificItem)
.forEach(item -> ((SpecificItem)item).also()));
stuff.stream().forEach(item -> item.method());
Es funktioniert gut, aber ich bin mit der "Instanz von" dort nicht zufrieden. Das ist im Allgemeinen ein Hinweis auf schlechten Codegeruch. Es ist sehr wahrscheinlich, dass ich diese Klasse umgestalten werde, nur um sie loszuwerden. Bevor ich jedoch etwas so Dramatisches mache, dachte ich, ich würde mich bei der Community erkundigen, ob jemand mit mehr Erfahrung mit Streams oder Sammlungen eine einfachere Lösung hat.
Ist es als Beispiel (sicherlich nicht exklusiv) möglich, eine Ansicht einer Sammlung zu erhalten, die Einträge nach Klassen filtert?
quelle
SpecificItem
müssen und dies der richtige Weg ist, um das Prädikat anzugeben, warum sind Sie dann zimperlich,instanceof
wenn Sie dort sind?.getKind()
oder.isSpecific()
?SpecificItem
Implementierung dann nicht erstalso()
zuerst aufgerufen wird?Iterable
hat keinestream()
Methode, aber Sie könnenforEach()
direkt auf eine aufrufenIterable
.Antworten:
Ich würde vorschlagen, einen
.map
Anruf zu tätigen , um die Besetzung für Sie zu erledigen. Dann kann Ihr späterer Code die "echte Sache" verwenden.Vor:
Nach:
Das ist nicht perfekt, scheint aber die Dinge ein wenig aufzuräumen.
quelle
stuff.stream().filter(item -> item instanceof SpecificItem).map(SpecificItem.class::cast).forEach(SpecificItem::also);
Das ist offensichtlich ein fehlerhaftes Design. Aus dem, was Sie geschrieben haben, geht nicht hervor, was es bedeutet, dass eine Klasse die Methode nicht implementiert . Wenn es einfach nichts tut , spielt es keine Rolle, daher gehe ich davon aus, dass es eine unerwünschte Nebenwirkung gibt.
Dein Mut ist richtig. Gutes objektorientiertes Design würde ohne weiteres Wissen funktionieren, was genau ein Objekt ist oder ob es sich um eine Instanz einer besonderen Art handelt.
Refactoring ist nicht dramatisch. Es verbessert die Codequalität.
Mit Ihrer angegebenen Codebasis wäre die einfachste Lösung, um sicherzustellen, dass Sie zwei separate Sammlungen haben, eine mit der übergeordneten und eine mit der untergeordneten Klasse. Das ist aber nicht ganz sauber.
quelle
Es ist schwer, spezifische Empfehlungen zu geben, ohne zu wissen, was
SpecificItem
und wasalso()
tatsächlich sind, aber:Definieren Sie
also()
auf der Oberklasse vonSpecificItem
. Geben Sie ihm eine Standardimplementierung, die nichts bewirkt (geben Sie ihm einen leeren Methodenkörper). Einzelne Unterklassen können es bei Bedarf überschreiben. Je nachdem, wasalso
tatsächlich ist, müssen Sie es möglicherweise in etwas umbenennen, das für alle beteiligten Klassen sinnvoll ist.quelle
eine Alternative:
Auf diese Weise können nur Objekte, die Ihre Schnittstelle implementieren, Themeselves an Ihre Methode übergeben. Sie müssen keine Instanz von verwenden
quelle
Ich hoffe, ich vermisse hier nichts Offensichtliches (auch wie in @Tristan Burnsides Kommentar vorgeschlagen ), aber warum kann ich nicht zuerst
SpecificItem.method()
anrufenalso()
?Ein Strom-y Weg , ich, auf Kosten der denken kann , vielleicht Auswirkungen einiger Leistung (YMMV), ist
collect()
überCollectors.groupingBy()
auf die Klasse als Schlüssel, dann wählen Sie, was Sie aus dem resultierenden wollenMap
. Die Werte werden als a gespeichert.List
Wenn Sie also damit gerechnet haben, eine solche Filterung für a durchzuführen,Set
und Sie hoffen, eine FilterungSet
daraus zu erhalten, benötigen Sie einen zusätzlichen Schritt, um die Werte auch in eine resultierende Filterung einzufügenSet
.quelle
Hier ist mein Ansatz:
Keine Instanz , keine expliziten Casts (eigentlich ist es eine explizite Cast, aber durch einen Methodenaufruf maskiert). Ich denke, das ist so gut wie es nur geht.
quelle