java 泛型观察者模式?
java generics observer pattern?
我知道有很多 (!) Q/A 关于这个一般话题;但还没有能够解决我的具体做法。
我从 Odersky 的 Scala 示例中改编了这段代码,它显示了相互递归的泛型类型,以显示 Observer 和 Observed 之间的双向 link 能力。
在 Subject::publish() 中,当我向所有观察者广播事件时,即使我的类型是 Subject,并且目标观察者是 类型,因此它也是通知方法;我收到类型错误,
The method notify(S) in the type Observer<S,O> is not applicable for
the arguments (Subject<S,O>)
除非我明确地将传递的参数转换为 notify()。
obs.notify( (S) this );
The types seem right, but the compiler disagrees(!).
可能有些愚蠢,但我不明白。 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);
}
- 构造
<S extends Subject<S, O>
确保只有类型Subject<S, O>
的子类型被允许作为类型参数,
这意味着 notify(S sub)
不能接受 Subject
class 本身,只能接受它的后代。
- 它确保子类型和 Subject 的实例化之间的继承关系是
Child extends Subject<Child, O>
的形式,这意味着像 Sensor extends Subject<NotASensorItself, O>
这样的子类型是不可能的(这是你真正想要的)
说到 Subject#publish
方法,通过使用 THIS
你有效地迫使观察者接受 Subject
(父)
它不符合声明的界限(S
≠ Subject<S, O>
)因此你得到了错误:
void publish() {
for (final O obs : observers)
obs.notify(this); <<< Here only S are acceptable
}
当您实际上希望 obs.notify(XXX)
接受一个 Clild 实例时,这样做的选项之一是将该引用与方法调用一起传递直接来自 Clid:
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`
}
}
一些可能有助于理解令人费解的递归类型的链接:
我知道有很多 (!) Q/A 关于这个一般话题;但还没有能够解决我的具体做法。
我从 Odersky 的 Scala 示例中改编了这段代码,它显示了相互递归的泛型类型,以显示 Observer 和 Observed 之间的双向 link 能力。
在 Subject::publish() 中,当我向所有观察者广播事件时,即使我的类型是 Subject,并且目标观察者是 类型,因此它也是通知方法;我收到类型错误,
The method notify(S) in the type Observer<S,O> is not applicable for the arguments (Subject<S,O>)
除非我明确地将传递的参数转换为 notify()。
obs.notify( (S) this ); The types seem right, but the compiler disagrees(!).
可能有些愚蠢,但我不明白。 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);
}
- 构造
<S extends Subject<S, O>
确保只有类型Subject<S, O>
的子类型被允许作为类型参数, 这意味着notify(S sub)
不能接受Subject
class 本身,只能接受它的后代。 - 它确保子类型和 Subject 的实例化之间的继承关系是
Child extends Subject<Child, O>
的形式,这意味着像Sensor extends Subject<NotASensorItself, O>
这样的子类型是不可能的(这是你真正想要的)
说到 Subject#publish
方法,通过使用 THIS
你有效地迫使观察者接受 Subject
(父)
它不符合声明的界限(S
≠ Subject<S, O>
)因此你得到了错误:
void publish() {
for (final O obs : observers)
obs.notify(this); <<< Here only S are acceptable
}
当您实际上希望 obs.notify(XXX)
接受一个 Clild 实例时,这样做的选项之一是将该引用与方法调用一起传递直接来自 Clid:
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`
}
}
一些可能有助于理解令人费解的递归类型的链接: