清洁解决方案"将"ObservableList <Foo>"强制转换为List <IFoo>?

gro*_*taj 2 java generics casting javafx interface

我的应用程序有一个简单的插件API.它打包在一个单独的JAR中,插件开发人员可以使用它.核心应用程序实现API中包含的接口,并将它们暴露给加载的插件ServiceLoader.

考虑以下代码:

public interface ILayer {}

public class Layer implements ILayer {
    public void internalMethod() { /*snip*/ }
}

public interface IPlotter {
    List<ILayer> getLayers();
}

public class Plotter implements IPlotter {
    private ObservableList<Layer> layers = FXCollections.observableArrayList();

    @Override
    public ObservableList<Layer> getLayers() {  // incompatible returned type
        return layers;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的要求是:

  • 在内部,ObservableListLayers是可用
  • API只公开了一个ListILayer小号

不幸的是,铸造ObservableList<Layer>List<ILayer>是违法的.

List<Layer>在API中返回会暴露internalMethod()出来Layer,所以这没有用.

我也可以private ObservableList<ILayer> layers,然后实际存储Layer内部,但这需要每次使用时都会投射它的项目internalMethod(),我对这个想法并不是很热心.

这个问题有一个干净的解决方案吗?

ass*_*ias 5

一种选择是更改接口方法的签名以允许返回ILayer的子类型:

interface IPlotter {
    List<? extends ILayer> getLayers();
}

class Plotter implements IPlotter {
    private ObservableList<Layer> layers = FXCollections.observableArrayList();

    @Override
    public List<? extends ILayer> getLayers() {
        return layers;
    }
}
Run Code Online (Sandbox Code Playgroud)

主要的缺点是有人调用List<? extends ILayer> layers = plotter.getLayers();将无法添加到列表:layers.add(someLayer);将无法编译.这可能是也可能不是问题.