0

我正在寻求实现一个主题观察者模式,其中主题在通知时向观察者提供自己。

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);
        }
    }
}

然而,实际上,这项工作,编译器在线上给出了Unchecked cast警告observer.update((T)this);

当阅读一点关于此的内容时,编译器是正确的(出乎意料),它甚至被认为是臭代码,因为您可以编写实际触发ClassCastException的代码。

现在我正在寻找一种不臭且坚如磐石的解决方案。然而,观察者不需要寻找它正在观察的主题的想法是我非常喜欢的。另外,我真的不喜欢观察者需要自己在他们的update(). 你对如何使用这个有什么建议吗?


编辑

我的观察者被声明为这样的接口:

public interface Observer<T> {
    void update(T subject);
}
4

1 回答 1

1

前言:我建议不要使用泛型——因为通过强制客户端(观察者)知道主题的确切类型(而不是拥有非泛型主题类),你不能例如。为同一个观察者订阅多个主题(不同类型)。

无论如何,有一种方法可以实现类型安全。


在通话中observer.update((T)this)你想要两件事:你想要传递this给观察者;而且您还希望 forthis成为 type T

在这一点上,this当然不能保证是类型T- 它是主题类型。但是“this”将是具体Subject类中的 T 类型。因此,替换thisgetThisSubject()并将其在层次结构中向下移动。在代码中:

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);
}

加上使用访问者或其他模式。(但这个回复已经足够长了)。

于 2018-06-10T16:06:51.283 回答