基于抽象类实现支持多Observer类型的泛型IObservable接口的多态函数方案咨询
你想要的这种复用register/remove逻辑、让子类仅提供对应Observer类型集合的思路是完全可行的,但当前的父类泛型方法设计和子类的重载方式不匹配,导致了编译错误。下面我会先解释问题的根源,再给出两种针对性的解决方案:
问题根源分析
你的ObservableBase中的protected abstract <O> Set<O> getCollection(O o)是一个泛型方法,它的签名意味着"对于任意类型O,传入O的实例就能返回对应的Set<O>"。而你在ConcreteClass中写的Set<Observer1> getCollection(Observer1 o)和Set<Observer2> getCollection(Observer2 o)是方法重载,并非方法重写——它们的签名和父类的泛型方法签名完全不匹配。
Java编译器会认为你没有实现父类的抽象泛型方法,因此抛出"Method does not override method from its superclass"的错误。退一步说,即使忽略编译错误,由于泛型擦除,父类registerObserver(O o)调用getCollection(o)时,o的编译时类型会被擦除为Object,最终会尝试调用父类的泛型方法,而非子类中重载的具体类型方法,这会导致运行时逻辑失效。
解决方案1:类型令牌+映射存储(灵活支持任意Observer类型)
调整ObservableBase的设计,内部用Map存储Observer类型与对应集合的映射关系,子类只需注册支持的Observer类型和集合,父类统一处理register/remove逻辑。
代码实现
1. 定义IObservable接口
public interface IObservable { <O> void registerObserver(O o); <O> void removeObserver(O o); }
2. 重构ObservableBase抽象类
import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public abstract class ObservableBase implements IObservable { // 线程安全的映射:Observer类型 -> 对应观察者集合 private final Map<Class<?>, Set<?>> observerMap = new ConcurrentHashMap<>(); // 子类必须实现该方法,注册支持的Observer类型与集合 protected abstract void initObserverCollections(); public ObservableBase() { initObserverCollections(); } @Override @SuppressWarnings("unchecked") public <O> void registerObserver(O o) { Class<?> observerType = o.getClass(); Set<O> collection = (Set<O>) observerMap.get(observerType); if (collection != null) { collection.add(o); } else { throw new IllegalArgumentException("不支持的观察者类型:" + observerType); } } @Override @SuppressWarnings("unchecked") public <O> void removeObserver(O o) { Class<?> observerType = o.getClass(); Set<O> collection = (Set<O>) observerMap.get(observerType); if (collection != null) { collection.remove(o); } } // 子类调用该方法注册观察者类型与集合 protected <O> void registerObserverType(Class<O> observerClass, Set<O> collection) { observerMap.put(observerClass, collection); } }
3. 实现ConcreteClass子类
import java.util.HashSet; import java.util.Set; public class ConcreteClass extends ObservableBase { private final Set<Observer1> observer1Set = new HashSet<>(); private final Set<Observer2> observer2Set = new HashSet<>(); @Override protected void initObserverCollections() { registerObserverType(Observer1.class, observer1Set); registerObserverType(Observer2.class, observer2Set); } // 示例:通知Observer1的逻辑 public void notifyObserver1s() { for (Observer1 observer : observer1Set) { observer.onEvent(); } } // 示例:通知Observer2的逻辑 public void notifyObserver2s() { for (Observer2 observer : observer2Set) { observer.onEvent(); } } }
方案优势
- 完全复用父类的
register/remove逻辑,子类仅需注册类型和集合 - 支持任意数量的Observer类型,扩展时无需修改父类代码
- 线程安全(使用
ConcurrentHashMap)
注意事项
- 当前实现仅匹配精确的Observer类型,若需要支持Observer的子类(如
Observer1Sub extends Observer1),可修改registerObserver中的逻辑,遍历observerMap的keySet寻找可分配的类型。 - 由于使用了
unchecked类型转换,子类需保证registerObserverType传入的Class与Set类型一致,避免类型转换错误。
解决方案2:泛型方法分发(固定少量Observer类型场景)
如果只需要支持固定数量的Observer类型,可以让父类的泛型getCollection方法根据传入对象的实际类型,分发到子类提供的具体集合方法中,严格遵循你最初的思路。
代码实现
1. 重构ObservableBase抽象类
import java.util.Set; public abstract class ObservableBase implements IObservable { @Override public <O> void registerObserver(O o) { getCollection(o).add(o); } @Override public <O> void removeObserver(O o) { getCollection(o).remove(o); } // 子类重写该泛型方法,根据o的类型返回对应集合 @SuppressWarnings("unchecked") protected <O> Set<O> getCollection(O o) { if (o instanceof Observer1) { return (Set<O>) getObserver1Collection(); } else if (o instanceof Observer2) { return (Set<O>) getObserver2Collection(); } else { throw new IllegalArgumentException("不支持的观察者类型:" + o.getClass()); } } // 子类必须实现这两个方法,返回对应类型的集合 protected abstract Set<Observer1> getObserver1Collection(); protected abstract Set<Observer2> getObserver2Collection(); }
2. 实现ConcreteClass子类
import java.util.HashSet; import java.util.Set; public class ConcreteClass extends ObservableBase implements IObservable<Observer1>, IObservable<Observer2> { private final Set<Observer1> observer1Set = new HashSet<>(); private final Set<Observer2> observer2Set = new HashSet<>(); @Override protected Set<Observer1> getObserver1Collection() { return observer1Set; } @Override protected Set<Observer2> getObserver2Collection() { return observer2Set; } // 重写具体类型的register/remove方法,让编译器做类型检查 @Override public void registerObserver(Observer1 o) { super.registerObserver(o); } @Override public void registerObserver(Observer2 o) { super.registerObserver(o); } @Override public void removeObserver(Observer1 o) { super.removeObserver(o); } @Override public void removeObserver(Observer2 o) { super.removeObserver(o); } }
方案优势
- 完全贴合你最初的设计思路,子类仅需实现集合获取方法
- 实现多
IObservable接口后,编译器会在调用registerObserver时做类型检查 - 父类复用了核心的
register/remove逻辑
注意事项
- 每次新增Observer类型,都需要修改
ObservableBase的getCollection方法,违反开闭原则,因此仅适合Observer类型固定的场景。
内容来源于stack exchange

