方法作为接口返回

时间:2018-07-02 12:59:40

标签: java

考虑以下示例:

我有3个接口:A,B,C,使用方法a(),b(),c();扩展基本接口Intf;

我有一个带有MyEnum.A,MyEnum.B,MyEnum.C选项的枚举;

我有一个扩展这3个接口的类:X实现A,B,C;

有一种方法可以在X中实现这样的方法;

public <T extends Intf> T getType (MyEnum enum)

结果是接口A,B或C,即仅访问方法a(),b()或c()?

编辑:我想在具有流畅api的构建器上使用它:

X var = X.getType(MyEnum.A).a("value").build();

X var = X.getType(MyEnum.B).b("value").build();

但从不

X var = X.getType(MyEnum.A).b("value").build(); //ERROR

3 个答案:

答案 0 :(得分:2)

您可以分派枚举值,并按照@GhostCat的建议返回匹配的实例。

您还可以反转查询,因此每个枚举值都提供Intf的适当实例

变量1 :每个枚举值的单例实例

public enum MyEnum {

    A(new AImpl()),
    B(new BImpl()),
    C(new CImpl());

    private Intf instance;

    MyEnum2(Intf instance) {
        this.instance = instance;
    }

    public <T extends Intf> T getType() {
        return (T) instance;
    }
}

变体2 :工厂,创建新实例:

public enum MyEnum {

    A(AImpl.class),
    B(BImpl.class),
    C(CImpl.class);

    private Class<? extends Intf> type;

    MyEnum(Class<? extends Intf> type) {
        this.type = type;
    }

    public <T extends Intf> T getType() {
        try {
            return (T) type.newInstance();
        } catch (InstantiationException | IllegalAccessException ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }
}

用法:

A a = MyEnum.A.getType();
B b = MyEnum.B.getType();
C c = MyEnum.C.getType();

答案 1 :(得分:1)

如果我正确阅读了您的问题,则需要

的编译时安全性
public <T extends Intf> T getType (MyEnum enum)

A返回MyEnum.A,为B返回MyEnum.B,等等。

如果使MyEnum类通用,则可以实现此编译时安全性。现在,此方法适用于普通枚举,但适用于老式的“类型安全枚举”模式。

假设我们有三个接口AABBCC扩展了基本接口II

public interface AA extends II { void a(); }
public interface BB extends II { void b(); }
public interface CC extends II { void c(); }

现在类TT实现所有这些接口:

public class TT implements AA, BB, CC {

    @Override
    public void a() { ... }

    @Override
    public void b() { ... }

    @Override
    public void c() { ... }

}

现在让EE为我们的通用伪枚举类,并使用II的某些子类型进行参数化:

public class EE<XX extends II> {

    public static final EE<AA> A = new EE<AA>();
    public static final EE<BB> B = new EE<BB>();
    public static final EE<CC> C = new EE<CC>();

}

使用这些定义,getType方法可以声明如下:

public <XX extends II> XX getType(EE<XX> enumVal)

此方法只能返回参数化enumVal的类型的类型。含义

AA type = tt.getType(EE.A);

有效,但

BB type = tt.getType(EE.A);

不是。

实现getType方法的一种方法是将TT实例的“转换”委托给AABBCC到对应的伪枚举:

public abstract class EE<XX extends II> {

    public static final EE<AA> A = new EE<AA>() {
        @Override
        public <PP extends AA & BB & CC> AA convert(PP instance) {
            return new AA() {
                public void a() {
                    instance.a();
                };
            };
        }
    };
    public static final EE<BB> B = new EE<BB>() {
        @Override
        public <PP extends AA & BB & CC> BB convert(PP instance) {
            return new BB() {
                public void b() {
                    instance.b();
                };
            };
        }
    };
    public static final EE<CC> C = new EE<CC>() {
        @Override
        public <PP extends AA & BB & CC> CC convert(PP instance) {
            return new CC() {
                public void c() {
                    instance.c();
                };
            };
        }
    };

    public abstract <PP extends AA & BB & CC> XX convert(PP instance);
}

您也可以直接返回instance,而无需包装在匿名内部类中。但是随后可以将结果强制广播到其他接口,从而允许访问其他方法。

最后,getType的实现很简单:

public <XX extends II> XX getType(EE<XX> enumVal) {
    return enumVal.convert(this);
}

据我所知,编译器不允许

BB bb = tt.getType(EE.A);

BB bb = (BB) tt.getType(EE.A);
bb.b();

无法像“在运行时生成ClassCastException时那样工作。

缺点是伪枚举构造和convert的实现有点难看。

答案 2 :(得分:0)

假设我们在类X中,那么您有一个本地通用参数,您可能会想到:

public <T extends Intf> T getType (MyEnum enumVal) {
  if (enumVal == MyEnum.A) {
    return (A) this;
  if (enumVal == MyEnum.B) {
    return (B) this;

但是您这样做没有任何收获。这些转换对调用方来说无关紧要。

因为在这里编译器无法为您做任何事情。你可以写

A someA = whatever.getType(someEnum);

但是你也可以写

B someB = whatever.getType(someEnum);

具有相同的someEnum。而且编译器会很高兴。

如果要获得“编译时安全性”的好处,则必须以某种方式将参数类型“连接”到结果类型。