没有使用泛型的观察者模式
No cast for observer pattern using generics
我一直在寻求实现一种主题观察者模式,其中主题在通知时向观察者提供自己。
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()
中进行演员表。您对此有何建议?
编辑
我的观察者被声明为这样的接口:
public interface Observer<T> {
void update(T subject);
}
前言:我建议不要使用泛型——因为通过强制客户(观察者)了解主题的确切类型,(而不是拥有非泛型主题 class),你不能,例如。将同一个观察者订阅到多个主题(不同类型)。
无论如何,有一种方法可以保证类型安全。
在调用 observer.update((T)this)
中你想要两件事:你想将 this
传递给观察者;并且您还希望 this
的类型为 T
.
在这一点上,this
当然不能保证是 T
类型——它是 Subject 类型。但是 "this" 在具体的 Subject
class 中将是类型 T。因此,将 this
替换为 getThisSubject()
并将其在层次结构中向下移动。在代码中:
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);
}
加上使用访问者或其他模式。 (但这个回复已经够长了)。
我一直在寻求实现一种主题观察者模式,其中主题在通知时向观察者提供自己。
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()
中进行演员表。您对此有何建议?
编辑
我的观察者被声明为这样的接口:
public interface Observer<T> {
void update(T subject);
}
前言:我建议不要使用泛型——因为通过强制客户(观察者)了解主题的确切类型,(而不是拥有非泛型主题 class),你不能,例如。将同一个观察者订阅到多个主题(不同类型)。
无论如何,有一种方法可以保证类型安全。
在调用 observer.update((T)this)
中你想要两件事:你想将 this
传递给观察者;并且您还希望 this
的类型为 T
.
在这一点上,this
当然不能保证是 T
类型——它是 Subject 类型。但是 "this" 在具体的 Subject
class 中将是类型 T。因此,将 this
替换为 getThisSubject()
并将其在层次结构中向下移动。在代码中:
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);
}
加上使用访问者或其他模式。 (但这个回复已经够长了)。