You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于抽象类实现支持多Observer类型的泛型IObservable接口的多态函数方案咨询

基于抽象类实现支持多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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:49:34