我正在寻求实现一种主题-观察者模式,其中主题在通知时向观察者提供其自身。
public class Subject<T extends Subject> {
/** suporting stuff for subject */
private List<Observer<T>> observers = new ArrayList<>();
protected void doNotify() {
for(Observer<T> observer : observers) {
/** This is the line where it gets interesting */
observer.update((T)this);
}
}
}
实际上,这项工作有效,但是编译器在 observer.update((T)this);
行上给出了 Unchecked cast 警告。
当阅读一些相关内容时,编译器是正确的(令人惊讶),甚至被认为是臭代码,因为您可以编写实际触发 ClassCastException 的代码。
现在我正在寻找一种没有异味且坚如磐石的解决方案。然而,我真的很喜欢观察者不需要寻找它正在观察的主题的想法。另外,我不太喜欢观察者需要在他们的 update()
中自己进行转换。您对如何进行此操作有什么建议吗?
编辑
我的观察者被声明为这样的接口(interface):
public interface Observer<T> {
void update(T subject);
}
最佳答案
前言:我建议不要使用泛型 - 因为通过强制客户端(观察者)了解主题的确切类型(而不是拥有非泛型主题类),您不能例如。将同一个观察者订阅多个主题(不同类型)。
无论如何,有一种方法可以实现类型安全。
<小时/>在调用 observer.update((T)this)
中,您需要两件事:您希望将 this
传递给观察者;并且您还希望 this
的类型为 T
。
此时,this
当然不能保证是 T
类型 - 它是Subject 类型。但“this”在具体的 Subject
类中将是 T 类型。因此,用 getThisSubject()
替换 this
并将其在层次结构中向下移动。在代码中:
package stackOv;
import java.util.*;
abstract class Subject<T extends Subject<T>> {
private List<Observer<T>> observers = new ArrayList<>();
// returns a reference of this, of type T
protected abstract T getThisSubject();
protected void doNotify() {
for(Observer<T> observer : observers) {
observer.update(getThisSubject());
}
}
public void addObserver(Observer<T> obs) {
observers.add(obs);
}
}
class SubjectA extends Subject<SubjectA> {
@Override
protected SubjectA getThisSubject() {
return this;
}
}
interface Observer<T> {
void update(T subject);
}
class UseSubject {
public static void main(String[] args) {
SubjectA sub = new SubjectA();
Observer<SubjectA> obs = new Observer<SubjectA>() {
@Override
public void update(SubjectA subject) {
//and here we have a reference to the right type
System.out.println("subj=" + subject);
}
};
sub.addObserver(obs);
sub.doNotify();
}
}
<小时/>
让我强调一下,我们正在将 Observer
类型与 Subject
类型耦合起来;他们确实是一对一的关系。避免这种情况的一种方法是声明 Subject
非泛型,并且
interface Observer {
void update(Subject subject);
}
加上使用访问者或其他模式。 (但是这个回复已经足够长了)。
关于java - 使用泛型无需强制转换观察者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50782041/