Предисловие: Я бы предложил НЕ использовать дженерики, потому что, заставляя клиентов (наблюдателей) знать точный тип Субъекта (в отличие от наличия неуниверсального класса Субъекта), вы не можете, например.подписать одного и того же наблюдателя на несколько субъектов (разных типов).
В любом случае, существует способ обеспечения безопасности типов.
В вызове observer.update((T)this)
вам нужны две вещи: вы хотите передать this
наблюдателям;и вы также хотите, чтобы this
имел тип T
.
. В этот момент, this
не гарантированно имеет тип T
, конечно, он имеет тип Subject.Но «это» будет иметь тип Т в конкретном Subject
классе.Поэтому замените 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);
}
плюс, используя посетитель или другие шаблоны.(но этот ответ уже достаточно длинный).