2016-07-17 22 views
0

Ich habe eine abstrakte Klasse 'Entity' und Objekte (die 'Entity' erweitern), die verschiedene Schnittstellen implementieren. Ich habe auch eine ArrayList, die all diese verschiedenen Objekte enthalten.Mehrere Listen oder Liste und getSublist() (Java)

Nun, wenn ich brauche Zugriff auf alle Unternehmen, die eine bestimmte Schnittstelle (verwenden seine Methoden) implementieren, verwende ich die folgende Methode (die eine gefilterte Liste von ‚Entitäten‘ zurückgibt, die Schnittstelle ‚IDirectFire‘ implementieren):

public ArrayList<IDirectFire> getDirectFireSublist() {//direct fire sublist 
    ArrayList<IDirectFire> sublist = new ArrayList(); 
    entities.stream().filter((it) -> (it instanceof IDirectFire)).forEach((it) -> { 
     sublist.add((IDirectFire) it); 
    }); 
    return sublist; 
} 

Jetzt zu meiner Frage: Sollte ich weiter mit dieser Methode arbeiten oder sollte ich eine neue ArrayList erstellen, die neben 'Entitäten' existiert und die ich jedes Mal manuell aktualisieren müsste, wenn 'Entitäten' geändert werden?

Ich muss 'Entitäten' viel aktualisieren, so dass ich nicht sicher bin, ob es effizienter ist, mehrere Unterlisten zu speichern und sie jedes Mal zu aktualisieren, wenn Entitäten geändert werden oder wenn ich weiterhin Methoden zum Filtern von 'Entitäten' und Wenden Sie Methoden auf diese Unterlisten an. Denken Sie daran, dass diese Unterlisten auch in anderen Methoden in einer Schleife verwendet werden würden, z. B.

Ist das machbar? Vielen Dank im Voraus!

+1

Im Allgemeinen sollte man versuchen zu entwerfen, um die Verwendung von 'instanceof' zu vermeiden, wo es möglich ist, da es als ein" Design-Geruch "gilt – wakjah

Antwort

0

Wenn Sie nur eine Teilmenge Ihrer Elemente durchlaufen müssen, ist das Erstellen einer neuen Liste verschwenderisch. Gib einfach den gefilterten Stream zurück.

public Stream<IDirectFire> getDirectFire() { 
    return entities.stream().filter((it) -> (it instanceof IDirectFire)); 
} 

Sie könnten auch Guava verwenden und zurückgeben eine gefilterte Iterable statt:

public Iterable<IDirectFire> getDirectFire() { 
    return FluentIterable.from(entities).filter(IDirectFire.class); 
} 

Dann Schleife über die Elemente elswhere:

private void resetFirestatusIDF() { 
    getDirectFire().forEach((it) -> it.dfHasFired(false)); 
} 
+0

Vielen Dank, obwohl ich momentan keine Guava benutze. Werft einen Blick darauf! – paxikek

+0

Die 'Filter (Klasse )' Methode in Guava ist ordentlich für das, was Sie tun, aber ansonsten ist die 'Stream' Methode genauso gut. Sie haben beide eine "forEach" -Methode, was bedeutet, dass das Looping-Beispiel für beide identisch ist. – Sam

0

Es ist besser, sie zu filtern. Es wird einen klareren und verständlichen Code zu einem Preis von vernachlässigbarem Leistungsabfall schaffen, der, wenn Sie Milliarden von Elementen filtern, vernachlässigbar sein sollte.

Das zweite, was ich bemerkt habe ist, dass Sie Verwendung für Codefragment streamen 1. Ich möchte Sie und alternativen Ansatz, um es empfehlen:

> public ArrayList<IDirectFire> getDirectFireSublist() { 
>  return entities.stream().filter((it) -> (it instanceof IDirectFire)).collect(Collectors.toList()); 
> } 
+0

Vielen Dank! Ich war mir nicht sicher, welchen Einfluss das auf die Leistung haben würde. – paxikek

1

Nun zu meiner Frage: Soll ich weiter mit dieser Methode arbeiten Oder soll ich eine neue ArrayList erstellen, die neben "entities" existiert und die ich jedes Mal manuell aktualisieren muss, wenn sich die Entitäten ändern?

Aus welchem ​​Grund möchten Sie die 'Daten' duplizieren?

1) Sie können sie nur in eine dedizierte Liste stellen. In diesem Fall brauchen Sie getDirectFireSublist() nicht länger.

2) Sie können sie zwischen den beiden Listen teilen, ohne sie zu duplizieren. In diesem Fall müssen Sie das hinzugefügte und das entfernte Entitätselement aktualisieren, da nur die geänderten Elemente aktualisiert werden. Aber es ist ziemlich direkt zu implementieren.

+0

Die neue Liste wäre kein Duplikat, sondern die gefilterten 'Entitäten' als eigene Liste, also meinte ich eine dedizierte Liste. Vielen Dank! – paxikek

0

wakjah in einem Kommentar erwähnt, dass instanceof ist ein bisschen Designgeruch. In diesem Sinne wäre eine alternative Lösung die Verwendung eines Besuchermusters.

public abstract class Entity { 
    public abstract void acceptVisitor(EntityVisitor visitor); 
    ... 
} 

public interface IDirectFire { 
    default acceptVisitor(EntityVisitor visitor) { 
     visitor.visit(this); 
    } 
    ... 
} 

public class ResetFireStatusVisitor implements EntityVisitor { 
    public void visit(IDirectFire directFireEntity) { 
     directFireEntity.dfHasFired(false); 
    } 
} 

Dann über die Elemente in einer Schleife:

entities.forEach(entity -> entity.acceptVisitor(new ResetFireStatusVisitor())); 

Die ResetFireStatusVisitor Anrufe dfHasFired(false) auf alles, was implementiert IDirectFire. In EntityVisitor können Sie Standard-No-Op-Implementierungen für die anderen Subtypen Entity angeben.

Ich schlage nicht vor, Sie tun dies für einfache Fälle, aber für groß angelegte Designs könnte dies eine sinnvolle Antwort auf dieses Problem sein. Auf der anderen Seite könnte es nicht sein - dieses Muster hat auch seinen Anteil an Designgerüchen.

+0

Darf ich fragen, warum instanceof Design-Geruch ist? Ich sehe definitiv die Nützlichkeit des Besuchers, nur neugierig. Ist die Instanz fehleranfälliger? Danke vielmals! – paxikek

+0

Zu groß, um ein Thema in einem Kommentar zu behandeln, aber es gibt viele Diskussionen da draußen. Hier ist das beste Suchergebnis: http://stackoverflow.com/questions/20589590/why-not-use-instanceof-operator-in-oop-design – Sam

+0

Yeah Entschuldigung, offensichtlich ein großes Thema, ich werde ein wenig suchen. Danke für den Link und deine Hilfe! – paxikek