2016-07-26 78 views
0

這是Java的一個問題。我有一個名爲IMyObjectPredicate它實現了一個單一的測試方法的接口適用於輸入:傳遞匿名類

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

我想什麼是能夠傳遞對象之間圍繞IMyObjectPredicate一個實例,並有test功能更新其引用到它傳遞給它的新對象的變量。例如,考慮一類利用這個斷言的:

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); 
    } 
} 

我想是能夠執行測試對象的深克隆的原因,我不會進入這裏。但是想法是Tester的克隆實例應該測試謂詞對其自己的myThreshold,而不是引用第一個實例的myThreshold。但是如果我通過myTestFunctionTester的新實例,我猜它仍然會引用第一個實例的myThreshold值,而不是根據封閉類的引用動態計算myThreshold

如何才能完成IMyObjectPredicate對象的通過,該對象的測試函數使用對新對象的字段的引用來傳遞給

編輯: 一個複雜的因素是,在一般情況下,它不會被可能從Tester對象內的字段重建myTestFunction完全。 myTestFunction可能會被程序的其他部分以與Tester的其他字段不相關的方式覆蓋。如果需要的話,我可以犧牲這種功能,但我寧願不爲高雅着想。

+1

我不希望這是可能的。但是如果它在構造函數中,你可以創建一個新的謂詞。 –

+0

@LouisWasserman通常,在程序過程中'myTestFunction'將被改變。我希望能夠根據需要按需複製它。 – Myridium

+0

「IMyObjectPredicate」的匿名impl有一個no-arg'test()'方法,但接口要求它採用'MyObject'參數...? –

回答

2

Java沒有API來替換匿名類的封閉上下文。

從簡單示例中可以看到的最簡單的解決方案是爲測試函數的簽名添加閾值。據我瞭解,無論如何,門檻將在那裏。

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

另一種方法是使用一些工廠方法,將創建一個謂語所提供的閾像

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

那麼你可以考績這家工廠爲對象,將使用它自己的門檻,構建新謂詞實例

factory.thresholdPredicate(myThreshold); 
+0

雖然這並未完全解決我的問題,但對於「Java沒有API來替換匿名類的封閉上下文」而言,+1。我從這個答案中得出的結論是,除非我實現一個顯式方法來重新構造新的Tester對象的字段,否則不可能以我想要的方式傳遞一個「IMyObjectPredicate」的副本。這是一個恥辱,因爲'Tester'字段通常不會確定謂詞應該是什麼。謂詞可以由程序的其他部分獨立修改。 – Myridium

0

如果ImObjectPredicate是一個簡單地存儲對謂詞的引用而不是接口的類。如果你能夠做出改變,每個謂詞都可以存儲自己的閾值,從而解決問題。

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); 
    } 
} 

這是最明智的解決方案,如ImObjectPredicate應該存儲其自己的閾值,如果這個值是指獨特的是該ImObjectPredicate

+0

根據對我的問題的更新,「ImObjectPredicate應該存儲自己的閾值,如果該值唯一地表示ImObjectPredicate」 - 不幸的是情況並非如此。 'Tester' **的字段不會**唯一確定'IMyObjectPredicate'。我可能會稍微簡化一下這個例子。 – Myridium