簡體   English   中英

java泛型觀察者模式?

[英]java generics observer pattern?

我知道關於這個一般主題有很多(!)Q/A; 但還沒有能夠解決我的具體方法。

我從 Odersky 的 Scala 示例中改編了這段代碼,該示例顯示了相互遞歸的泛型類型,以顯示 Observer 和 Observed 之間的雙向鏈接能力。

在 Subject::publish() 中,當我向所有觀察者廣播事件時,即使我的類型是 Subject<S,O>,並且目標觀察者的類型是 <S,O>,因此也是它的 notify 方法; 我收到一個類型錯誤,

Observer<S,O> 類型中的方法 notify(S) 不適用於參數 (Subject<S,O>)

除非我顯式地將傳遞的參數強制轉換為 notify()。

obs.notify((S) this ); 類型看起來是正確的,但編譯器不同意(!)。

可能有些愚蠢,但它讓我望而卻步。 TIA

abstract class Subject< S extends Subject<  S, O >,
                        O extends Observer< S, O > > {
    private final List< O > observers = new ArrayList<O>();
    void subscribe( O obs ) { observers.add( obs ); }
    void publish() {
        for ( final O obs : observers )
            // TThe method notify(S) in the type Observer<S,O> is not applicable for the arguments (Subject<S,O>)
            obs.notify( this ); // (S)this   ??
    }
}
//-------------------------------------------------------------
abstract class Observer< S extends Subject<  S, O >,
                         O extends Observer< S, O > > {
    abstract void notify( S sub );
}
//-------------------------------------------------------------
class Sensor extends Subject< Sensor, Display > {
    double value = 0.0;
    String name  = "";
    Sensor(String nm) { name = nm; }
    
    void changeValue( final double v ) {
        value = v;
        publish();
    }
    public String toString() { return "Sensor:" + name; }
}

class Display extends Observer< Sensor, Display > {
    void notify( Sensor sub ) {  // Note typed argument!
        System.out.println( sub  + " has value " + sub.value );
    }
}
//-------------------------------------------------------------
public class SubjectObserver {
    public static void main( final String[] notUsed ) {
        final Display o = new Display();
        final Sensor  s = new Sensor("Temperature");
        s.subscribe( o );
        s.changeValue( 1 );
    }
}

你幾乎做對了!

自有界(或遞歸)類型聲明暗示了幾個微妙的細微差別。 鑒於您的觀察者聲明,我們可以聲明:

abstract class Observer<S extends Subject<S, O>, O extends Observer<S, O>> {
    abstract void notify(S sub);
}
  1. 構造<S extends Subject<S, O>確保只允許類型Subject<S, O>子類型作為類型參數,這意味着notify(S sub)不能接受Subject類本身,而只能接受它的后代。
  2. 它確保子類型和 Subject 的實例化之間的繼承關系是Child extends Subject<Child, O>的形式Child extends Subject<Child, O>這意味着像Sensor extends Subject<NotASensorItself, O>這樣的子類型是不可能的(這就是你真正想要的)

說到Subject#publish方法,通過使用THIS你有效地強迫觀察者接受不符合聲明界限( SSubject<S, O> )的Subject (父),因此你得到了錯誤:

void publish() {
    for (final O obs : observers)
        obs.notify(this); <<< Here only S are acceptable
}
    

實際上,當您希望obs.notify(XXX)接受Clild實例時,這樣做的選項之一是直接傳遞該引用以及來自Clild的方法調用:

void publish(S subject) {
    for (final O obs : observers)
        obs.notify(subject);
}

和傳感器實現:

class Sensor extends Subject<Sensor, Display> {
    ...
    void changeValue(final double v) {
        value = v;
        publish(this); << Here it passes itself, so now it conforms the bound for `S`
    }
}

一些可能有助於理解令人費解的遞歸類型的鏈接:

  1. http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106
  2. https://medium.com/@hazraarka072/fluent-builder-and-powering-it-up-with-recursive-generics-in-java-483005a85fcd

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM