2016-07-26 16 views
0

Dies ist eine Frage für Java. Ich habe eine Schnittstelle IMyObjectPredicate genannt, die ein einzelnes Testverfahren implementiert, um eine Eingabe gelten:Anonyme Klassen übergeben

public interface IMyObjectPredicate { 
    boolean test(MyObject x); 
} 

Was würde Ich mag in der Lage sein, eine Instanz von IMyObjectPredicate passieren um zwischen Objekten und haben die test Funktion aktualisieren ihre Referenzen zu den Variablen des neuen Objekts, an das es übergeben wird. Betrachten wir zum Beispiel eine Klasse, die Verwendung dieses Prädikat macht:

public class Tester { 
    MyObject o; 
    IMyObjectPredicate myTestFunction; 
    int myThreshold; 

    public Tester(/*stuff*/) { 
     /*Code here which initialises the Tester instance and 'myThreshold'*/ 
     myTestFunction = new IMyObjectPredicate() { 
      @Override 
      public boolean test(MyObject o) { 
       return (o.value() > myThreshold); 
      } 
     }; 
    } 

    pubic boolean isGood() { 
     return myTestFunction.test(o); 
    } 
} 

würde ich einen tiefen Klon in der Lage sein mag des Testers Objekt auszuführen aus Gründen, die ich hier nicht näher eingehen. Aber die Idee ist, dass die geklonte Instanz von Tester das Prädikat gegen seinen eigenen Wert von myThreshold testen sollte, nicht die myThreshold der ersten Instanz verweisen. Aber wenn ich myTestFunction an eine neue Instanz von Tester übergebe, denke ich, dass es immer noch den Wert myThreshold der ersten Instanz referenzieren wird, anstatt myThreshold basierend auf der Referenz der einschließenden Klasse dynamisch zu bewerten.

Wie kann ich die Übergabe eines IMyObjectPredicate Objekts erreichen, dessen Testfunktion Verweise auf die Felder des neuen Objekts verwendet, das an übergeben wird?

Edit: Erschwerend kommt hinzu, dass in der Regel wird es nicht möglich sein myTestFunction aus den Bereichen innerhalb eines Tester Objekt nur zu rekonstruieren. myTestFunction kann von anderen Teilen des Programms in einer Weise überschrieben werden, die nicht mit den anderen Feldern von Tester korreliert. Ich kann diese Funktionalität opfern, wenn es sein muss, aber ich würde lieber nicht wegen der Eleganz.

+1

Ich würde nicht erwarten, dass dies möglich ist.Aber wenn es im Konstruktor ist, können Sie einfach ein neues Prädikat erstellen. –

+0

@LouisWasserman Im Allgemeinen wird 'myTestFunction' im Laufe des Programms geändert. Ich möchte es bei Bedarf nach Bedarf kopieren können. – Myridium

+0

Ihr anonymer Impl von 'IMyObjectPredicate' hat eine no-arg' test() 'Methode, aber die Schnittstelle benötigt ein' MyObject' Argument ...? –

Antwort

2

Java hat keine API, um den geschlossenen Kontext der anonymen Klasse zu ersetzen.

Die einfachste Lösung, die ich aus Ihrem vereinfachten Beispiel sehen kann, besteht darin, der Signatur der Testfunktion einen Schwellenwert hinzuzufügen. Wie ich verstehe, wird die Schwelle sowieso da sein.

public interface IMyObjectPredicate { 
    boolean test(MyObject x, int threshold); 
} 

Ein anderer Ansatz wäre eine Factory-Methode verwenden, die ein Prädikat für bereitgestellt Schwelle wie

class PredicateFactory { 
    IMyObjectPredicate thresholdPredicate(int threshold) { 
     return new IMyObjectPredicate { 
       //... 
     } 
    } 
} 

schaffen wird, dann können Sie dieses Werk pas dass zum Objekt wird seine eigene Schwelle verwenden, um neue zu bauen Instanz von Prädikat

factory.thresholdPredicate(myThreshold); 
+0

Obwohl dies mein Problem nicht vollständig löst, +1 für "Java hat keine API, um den geschlossenen Kontext der anonymen Klasse zu ersetzen". Was ich von dieser Antwort wegnehme, ist, dass es nicht möglich ist, eine Kopie von 'IMyObjectPredicate' auf die gewünschte Weise zu übergeben, es sei denn, ich implementiere eine explizite Methode zur Rekonstruktion des Prädikats aus den Feldern des neuen 'Tester'-Objekts. Dies ist eine Schande, da die "Tester" -Felder im Allgemeinen nicht bestimmen, was das Prädikat sein sollte. Das Prädikat kann unabhängig von anderen Teilen des Programms modifiziert werden. – Myridium

0

Es ist viel einfacher, wenn ImObjectPredicate ist eine Klasse, die einfach einen Verweis auf ein Prädikat statt auf eine Schnittstelle speichert. Wenn Sie diese Änderung vornehmen können, kann jedes Prädikat seinen eigenen Schwellenwert speichern, der das Problem löst.

public IMyObjectPredicate { 
    private int threshold; 
    private Predicate<MyObject> pred; 

    public int getThreshold() { 
     return threshold; 
    } 

    public Predicate<MyObject> getPredicate() { 
     return pred; 
    } 

    public IMObjectPredicate(int threshold, Predicate<MyObject> pred) { 
     this.threshold = threshold; 
     this.pred = pred; 
    } 

    public boolean test(MyObject o) { 
     return pred.test(o); 
    } 
} 

public class Tester { 
    MyObject o; 
    IMyObjectPredicate myTestFunction; 
    IMyObjectPredicate myTestFunctionCopyWithDiffThreshold; 
    int myThreshold; 

    public Tester(/*stuff*/) { 
     /*Code here which initialises the Tester instance and 'myThreshold'*/ 
     myTestFunction = new IMyObjectPredicate(myThreshold, o -> o.value() > getThreshold()); 
     myTestFunctionCopyWithDiffThreshold = new ImObjectPredicate(5, myTestFunction.getPredicate()); 
    } 

    pubic boolean isGood() { 
     return myTestFunction.test(o); 
    } 
} 

Dies ist die sinnvolle Lösung, wie ImObjectPredicatesollte Speicher seine eigene Schwelle, wenn dieser Wert bezieht sich eindeutig, daß diese ImObjectPredicate.

+0

Laut dem Update zu meiner Frage, "ImObjectPredicate sollte seinen eigenen Schwellenwert speichern, wenn dieser Wert bezieht sich eindeutig auf das ImObjectPredicate" - das ist leider nicht der Fall. Die Felder "Tester" ** bestimmen nicht eindeutig das "IMyObjectPredicate". Ich habe das Beispiel vielleicht ein wenig vereinfacht. – Myridium

Verwandte Themen