请考虑以下代码:
public abstract class Subject {
private Collection<Observer> observerCollection = new HashSet<>();
// ...
protected void notifyObservers() {
this.observerCollection.stream().filter(Objects::nonNull).forEach(o -> o.update(this));
}
}
public interface Observer<T extends Subject> {
void update(T subject);
}
我收到以下编译时警告:
观察者是原始类型。对泛型类型Observer的引用应该参数化
类型安全:方法更新(主题)属于原始类型Observer。对泛型类型Observer的引用应该参数化
一个人来到了update
,在我的生命中,我无法弄清楚如何在不使用警告抑制的情况下解决它。我已经尝试了几种方法来解决警告而没有运气。关于如何解决这个问题的任何想法?
考虑以下客户端代码:
public class IntegerContainer extends Subject {
private int integer;
public IntegerContainer(int integer) {
this.integer = integer;
}
public int getInteger() {
return this.integer;
} // ...
}
public class IntegerObserver implements Observer<IntegerContainer> {
private int cachedInteger;
@Override
public void update(IntegerContainer subject) {
this.cachedInteger = subject.getInteger(); // avoid cast here.
} // ...
}
在Observer
中使用泛型的动机是避免对subject
参数进行强制转换,以便观察者可以检索主题的状态。
答案 0 :(得分:2)
这与流没有任何关系;它只是直接赢得了工作。
Observer<? extends Subject>
或多或少无法使用,因为您不知道它是Subject
的哪个子类型的观察者。如您所知,observerCollection
仅包含Observer<SomeSubtypeOfSubjectThatNobodyEvenHeardOf>
。 (请参阅PECS principle; Observer
是消费者。)
我坦率地说,我认为没有任何类型安全的方法可以干净利落地执行此操作,因为您无法在Subject
中说出附加的观察者都接受这个主题的子类型,因为没有办法引用&#34;这个主题的子类型。&#34;我能想到的最接近的黑客是
abstract class Subject<T extends Subject<T>> {
private Collection<Observer<? super T>> observers;
protected void notifyObservers() {
this.observerCollection.stream().filter(Objects::nonNull).forEach(o -> o.update((T) this)); // yes, this cast is unchecked
}
}
class SubSubject extends Subject<SubSubject> {
...
}
答案 1 :(得分:0)
我专注于Subject
和Observer
之间传递的价值。即这两个类都有一个类型参数,相关方法确保类型兼容:
public interface Observer<T> {
void update(T value); // no subject, but a value
}
public class Subject<T> {
private Collection<Observer<? super T>> observers = new HashSet<>();
protected void notifyObservers() {
this.observers.stream().filter(Objects::nonNull).forEach(o -> o.update(this.getValue()));
}
public void addObserver(Observer<T> observer) { // adding the right kind of observer
observers.add(observer);
}
abstract public T getValue(); // returning the value - this one is abstract
}
上面的关键是abstract public T getValue();
方法。您可以通过以下方式撰写IntegerContainer
和IntegerObserver
:
public class IntegerContainer extends Subject<Integer> {
private int value;
public IntegerContainer(int value) {
this.value = value;
}
@Override
public Integer getValue() {
return value; // this is the parameter of the update() call
// you could even compute here something
// you can pass entire objects too, if required
}
}
public class IntegerObserver implements Observer<Integer> {
private int cachedInteger;
@Override
public void update(Integer value) {
this.cachedInteger = value; // no cast here
} // ...
}
你可以把它们放在一起:
IntegerContainer container = new IntegerContainer(3);
IntegerObserver observer = new IntegerObserver();
container.addObserver(observer);
container.notifyObservers();