2012-04-09 3 views
1

Ich habe eine Liste von MyObjects die ich in drei Gruppen zu unterteilen müssen:OO Muster eine Sammlung in Gruppen zum Teil

  1. gut bekannt (halten)
  2. schlecht bekannt (ablehnen)
  3. unerkannte (erhöhen alert)

MyObject enthält verschiedene Eigenschaften, die das Objekt in setzen, die der 3 Gruppen zu prüfen ist, um festzustellen.

Meine erste Implementierung (Java) nimmt nur eine Liste in ihrem Konstruktor und führt die Triage dort durch. Pseudo-Code:

class MyObjectFilterer { 
    public MyObjectFilterer(List<MyObject> list) { 
    // triage items here 
    } 
    public List<MyObject> getGood() { 
    // return sub-list of good items 
    } 
    public List<MyObject> getBad() { 
    // return sub-list of bad items 
    } 
    public List<MyObject> getUnrecognized() { 
    // return sub-list of unrecognized items 
    } 
} 

Probleme mit dieser Implementierung? Gibt es eine bessere OO-Wahl?

Antwort

2

Ich würde wahrscheinlich eine statische Factory-Methode bevorzugen, um die Filterung durchzuführen, die dann einen privaten Konstruktor aufruft, der die drei gefilterten Listen nimmt und der guten Code-Praxis folgt, niemals ernsthaft in einem Konstruktor zu arbeiten. Ansonsten sieht das gut aus.

+0

Ich weiß, dass Sie die übermäßige Verwendung oder falsche Verwendung von Guava-Funktionsparadigmen nicht im Griff haben, aber als Teil des Guava-Teams schlagen Sie nicht die Verwendung von 'Predicate's und' Iterables.filter() vor '? –

+0

Absolut nicht. Zunächst möchte das OP die Liste in drei verschiedene Kategorien aufteilen. Selbst mit 'Iterables.filter' würde das OP 'Prädikat 's, nicht' Funktion 'verwenden und daran denken, dass es keine' Lists.filter'-Methode gibt - das würde drei Durchläufe der Zielliste erfordern eher als ein einzelner. Nicht nur, dass funktionale Idiome dies weniger lesbar machen, es würde es auch strikt weniger effizient machen. –

+0

Ich war gerade dabei, meinen Beitrag zu bearbeiten, um Prädikate zu verwenden, bevor ich Ihre Antwort sah. Ich sehe Ihren Standpunkt, wie es für die Frage gilt, wie direkt gefragt. Ich denke, ich dachte nach, was hinter der Frage möglich war. Ist das Ziel tatsächlich, drei physische Sammlungen zu haben, oder war das Ziel, ein Mittel zu haben, um jedes Element einer einzelnen Sammlung nach Bedarf zu klassifizieren? Wenn Letzteres der Fall wäre, wäre es dann immer noch unangemessen, die Verwendung von Prädikaten als verteilte Klassifikatoren vorzuschlagen, wenn Sie den zu klassifizierenden Objekten keine Logik hinzufügen wollen? –

0

Es kann mehrere Ansätze geben. Wenn das Problem generisch/wiederholend genug ist, könnten Sie eine Schnittstelle mit einer Methode zum Klassifizieren der Objekte definieren.

interface Selector { 
    public boolean isGood(MyObject myObject); 
    public boolean isBad(MyObject myObject); 
    public boolean isUnknown(MyObject myObject); 

}

diese Weise können Sie leicht die Logik Implementierung ändern könnte.

0

Eine andere Idee wäre die Kette der Verantwortung.

Ihre MyObjectFilterer enthält einen Verweis auf drei Objekte GoodFilterer, BadFilterer und UnrecognizedFilterer. Jede von ihnen enthält die folgenden Methoden: addMethod (MyObject Objekt), getObjects() und addFilter(). Natürlich müssen sie eine Schnittstelle implementieren Filterer.

Mit der addFilter Methode können Sie die Kette bauen. so dass die GoodFilterer enthält einen Verweis auf die BadFilterer und dieser enthält zum UnrecognizedFilterer

Jetzt können Sie durch die Liste gehen von MyObjects und rufen Sie die Add-Methode auf dem GoodFilterer eine Referenz (erster in dieser Kette). Innerhalb der Add-Methode entscheiden Sie, ob das gut ist, als Sie es behalten und die Arbeit beenden, wenn Sie es nicht weiterleiten an die BadFilterer.

Sie behalten Ihre drei Methoden für die gut/schlecht und unerkannt bekommen, aber Sie werden diese getObjects auf die() übergeben Methode des filterer

Der Nutzen entspricht, dass die Logik, wenn dies ein guter/schlechter oder Unerkannter ist jetzt getrennt.

Der Nachteil wäre, dass Sie 3 neue Klassen und 1 Schnittstelle benötigen.

Aber wie ich schon sagte, das ist nur eine andere Idee, was Sie tun könnten.

+1

Es scheint, dass die Kategorien in diesem Fall sich gegenseitig ausschließen und daher möglicherweise voneinander abhängig sind (d. H. Nur schlecht oder nicht erkannt werden können, wenn zuerst bekannt wird, dass sie NICHT gut ist). Ich bin mir also nicht sicher, ob Sie die Logik für die Berechnung gut/schlecht/nicht erkannt –

0

Sie sollten vereinfachen, wie es möglich ist. Machen Sie einfach statische Methode in MyObjectFilter mit folgender Signatur:

öffentliche statische Liste filterMyObjects (List data, Group group).

Gruppe Aufzählung mit drei Werten, und es kann ich vielleicht

+0

wahrscheinlich nicht gut trennen möchten, um die Enumeration zu einer Eigenschaft der Objekte zu machen, denn wenn die Objekte andere veränderbare Felder in der Kategorisierung verwenden, könnte sich ihre Klassifizierung ändern und Sie müssten die Kategorisierungseigenschaft synchron mit allen Änderungen am Objekt halten. Es ist besser, die Kategorisierungslogik/-Eigenschaften außerhalb der Klasse zu behalten. –

+0

Entschuldigung, ich habe aus Ihrer Frage nicht alles richtig verstanden. Ich dachte, Gruppe gehört eigentlich in deiner Klasse als Feld. Ich würde immer noch bevorzugen, eine statische Methode zu haben und Gruppennumerierung (umbenannt in FilterOption) als Argument der Methode zu verwenden. –

0

als Attribut von MyObject-Klasse verwendet werden versuchen, so etwas wie:

enum MyObjectStatus { 
    GOOD, BAD, UNRECOGNIZED; 
} 

class MyObjectFilterer { 
    private MyObjectStatus getStatus(MyObject obj) { 
    // classify logic here, returns appropriate enum value 
    } 

    // ListMultimap return type below is from Google Guava 
    public ListMultimap<MyObjectStatus, MyObject> classify(List<MyObject> objects) { 
    ListMultimap<MyObjectStatus, MyObject> map = ArrayListMultimap.create(); 
    for(MyObject obj: objects) { 
     map.put(getStatus(obj), obj); 
    } 
    } 
} 

Anruf Klassifizieren() eine Multimap zu bekommen, und jede Kategorie extrahieren wie mit so etwas wie benötigt:

List<MyObject> good = map.get(GOOD); 
List<MyObject> bad = map.get(BAD); 
List<MyObject> unknown = map.get(UNRECOGNIZED); 

Eine nette Sache über diese Lösung Sie müssen nicht erstellen/Zugriffsmethoden für jede Kategorie veröffentlichen (es sei denn, Sie möchten), und Wenn neue Kategorien erstellt werden, fügen Sie auch keine neuen Zugriffsmethoden hinzu - nur die neue Enumeration und die zusätzliche Klassifikatorlogik.