通过设计强制其实现者的未知方法的输出类型的Java接口



目前,我已经定义了一个接口X,它由其他一些接口实现(只是为了在其他地方识别它们)。

所有实现X的接口都可以提供尽可能多的公共方法,但我想通过设计/架构强制执行,所有这些方法(再次注意它们对X是未知的)都将返回一个派生自相同抽象类y的类型。

有什么方法可以在Java中实现吗?

在下面的例子中,X应该强制U和v只返回从Y派生的类型

public interface X {
    // I'm empty at present.
}
public interface U extends X {
    public A getA();
    public B getB(String bIn);
}
public interface V extends X {
    public C getC(Integer cIn);
    public D getD(); // Compile should fail!
}
public class A extends Y {
}
public class B extends Y {
}
public class C extends Y {
}
public class D {
    // D does *not* extend Y.
}

没有办法在java类型系统中强制执行这一点。因此,您将留下:

    反射
  • 定制静态分析
  • 代码审查&开发人员教育

我会远离反射和静态分析。您还没有说明要用这个方法解决什么问题,因此很难给出任何替代方法。

我同意@fge的观点,这听起来像是XY问题,但我认为您可能能够在编译时得到一些工作。

你想对一个类型的每个方法都有一个需求,但是Java只允许你指定存在一些方法满足一个类型的一些需求,所以你将不得不重构UV

在设置中,我让X指定任何实现者必须提供返回Y后代的方法。我还指定了Y是一个抽象类。

interface X {
    Y getY();
}
abstract class Y {
}
然后,我看了你的接口UV,以及它们的方法U#getA(), U#getB(String), V#getC(Integer), V#getD()。所有这些方法都可以放在它们自己的类中。
class UA implements X {
    public A getY() {
        ...
    }
}
class UB implements X {
    private final String s;
    public UB(String s) {
        this.s = s;
    }
    public B getY() {
        ...
    }
}
class VC implements X {
    private final Integer integer;
    public VC(Integer integer) {
        this.integer = integer;
    }
    public C getY() {
        ...
    }
}
// COMPILE-TIME ERROR
class VD implements X {
    public D getY() {
        ...
    }
}

现在,任何实现X的东西都必须提供y。现在的问题是UA, UB, VCVD可以提供其他方法。您已经说过,您只希望它们提供返回Y的方法。为了解决这个问题,您可以用final具体类替换X,该类只提供一个您可以控制的构造函数。

X替换为YFactory(代码中的所有地方)

interface YFactory {
    Y getY();
}

现在,将X指定为只有一个构造函数的具体类:

final class X {
    private final YFactory yFactory;
    public X(YFactory yFactory) {
        this.yFactory = yFactory;
    }
    public Y getY() {
        return yFactory.getY();
    }
}

一起:

final class X {
    private final YFactory yFactory;
    public X(YFactory yFactory) {
        this.yFactory = yFactory;
    }
    public Y getY() {
        return yFactory.getY();
    }
}
abstract class Y {
}
interface YFactory {
    Y getY();
}
class A extends Y {
}
class B extends Y {
}
class C extends Y {
}
class D {
    // D does *not* extend Y.
}
class UA implements YFactory {
    public A getY() {
        return null;
    }
}
class UB implements YFactory {
    private final String s;
    public UB(String s) {
        this.s = s;
    }
    public B getY() {
        return null;
    }
}
class VC implements YFactory {
    private final Integer integer;
    public VC(Integer integer) {
        this.integer = integer;
    }
    public C getY() {
        return null;
    }
}
class VD implements YFactory {
    public D getY() {
        return null;
    }
}

现在您知道任何X都只有返回Y的方法。

最新更新