Java泛型中基于其他两种类型推断返回类型的更简单方法

Java泛型中基于其他两种类型推断返回类型的更简单方法,java,generics,interface,Java,Generics,Interface,我在Java中尝试做的基本上是拥有一个由两个其他接口组合而成的接口(因此它有来自这两个接口的方法,但没有自己的),然后两个子接口可以一次交换一个,因此当进行更改时,两个接口之一的所有方法都会保留,而来自另一个接口的所有方法都被交换为不同的方法。由于泛型处理开关,因此不需要强制转换来获得新方法或删除旧方法 例如,我们从接口AA开始,它是接口LeftA和RightA的组合,给它方法methodLeftA和methodRightA,然后我们调用selectLeftType(B)现在我们有了接口BA,它

我在Java中尝试做的基本上是拥有一个由两个其他接口组合而成的接口(因此它有来自这两个接口的方法,但没有自己的),然后两个子接口可以一次交换一个,因此当进行更改时,两个接口之一的所有方法都会保留,而来自另一个接口的所有方法都被交换为不同的方法。由于泛型处理开关,因此不需要强制转换来获得新方法或删除旧方法

例如,我们从接口
AA
开始,它是接口
LeftA
RightA
的组合,给它方法
methodLeftA
methodRightA
,然后我们调用
selectLeftType(B)
现在我们有了接口
BA
,它是接口
LeftB
RightA
的组合,提供了方法
methodLeftB
methodRightA
。对于泛型,这基本上允许我执行以下操作:
getStartState().methodLeftA().methodRightA().selectLeftType(B.methodLeftB().methodRightA()

我已经为此设计了一个实现,它确实可以工作,我将在这里进一步展示,但是代码非常冗长。只需执行类型A、B和C。已经有30个文件,要添加D,需要添加16个新文件和编辑17个现有文件。在这之后添加E需要添加20个新文件和编辑26个现有文件。因此,虽然这对于一小部分选项来说是可以接受的,但它很快就会失去控制,而不仅仅是几个选项。所以我的问题是,有没有更简单、更干净的方法

注意:这是使用Java7构建的,但我对使用Java8特性的实现持开放态度

我当前的实现如下(如我前面所说,它很长):

BaseImpl.java

package test;

class BaseImpl<CURRENT_INTERFACE> implements Combo<CURRENT_INTERFACE> {

  protected <T extends Combo<?>> T 
      selectLeftTypeBase(Selector<?, ?, ?, ?, ?, ?> selector, Class<T> cls) {
    System.out.println("Switch left type.  New class: " + cls.getSimpleName());
    return selectTypeBase(cls);
  }

  protected <T extends Combo<?>> T 
      selectRightTypeBase(Selector<?, ?, ?, ?, ?, ?> selector, Class<T> cls) {
    System.out.println("Switch right type. New class: " + cls.getSimpleName());
    return selectTypeBase(cls);
  }

  private <T extends Combo<?>> T selectTypeBase(Class<T> cls) {
    try {
      return cls.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
      e.printStackTrace();
    }
    return null;
  }

  @SuppressWarnings("unchecked")
  public CURRENT_INTERFACE methodLeftA() {
    System.out.println("Left A specific stuff.");
    return (CURRENT_INTERFACE) this;
  }

  @SuppressWarnings("unchecked")
  public CURRENT_INTERFACE methodLeftB() {
    System.out.println("Left B specific stuff.");
    return (CURRENT_INTERFACE) this;
  }

  @SuppressWarnings("unchecked")
  public CURRENT_INTERFACE methodLeftC() {
    System.out.println("Left C specific stuff.");
    return (CURRENT_INTERFACE) this;
  }

  @SuppressWarnings("unchecked")
  public CURRENT_INTERFACE methodRightA() {
    System.out.println("Right A specific stuff.");
    return (CURRENT_INTERFACE) this;
  }

  @SuppressWarnings("unchecked")
  public CURRENT_INTERFACE methodRightB() {
    System.out.println("Right B specific stuff.");
    return (CURRENT_INTERFACE) this;
  }

  @SuppressWarnings("unchecked")
  public CURRENT_INTERFACE methodRightC() {
    System.out.println("Right C specific stuff.");
    return (CURRENT_INTERFACE) this;
  }

}
Left.java

package test;

public interface Left<CURRENT_INTERFACE> { }

老实说,这太长了——tl;但是总的来说,听起来你在这件事上太聪明了。亲爱的上帝。如果这使您的船漂浮起来,您可以查看注释处理……它可以生成代码,并且您可以以编程方式完成所有这些工作。注释处理有点有限(没有黑客就无法修改现有代码),但它可以做这类事情。或者写一些输出文本的东西。关键是,若你们正在做的工作是可行的,但它太大了,无法手工编写,那个么代码生成就是一种选择。当然,我要说的是Java泛型并不擅长这类事情,当且仅当实现这些接口的每个类都实现了所有这些接口时,这个方案才能可靠地工作而不会出错。在这种情况下,为什么它们是独立的接口?这似乎是一件非常奇怪的事情,而你的匿名样本并没有给出你为什么要这么做的线索。你真正的用例是什么?@yshavit这就是问题的关键所在。这太长了,有没有办法把它变小?如果它更小,那么一开始就不会有问题:P,但是是的,这就是为什么我在给出实现细节之前问这个问题的原因。正如它目前所说的,代码太长,太复杂了,无法在任何一种生产代码中考虑使用。老实说,只要程序员不必编写或维护它,就没有人关心复杂性。如果可以使用注释在幕后生成代码。。。我得调查一下,看看有什么可能。老实说,这太长了——tl;但是总的来说,听起来你在这件事上太聪明了。亲爱的上帝。如果这使您的船漂浮起来,您可以查看注释处理……它可以生成代码,并且您可以以编程方式完成所有这些工作。注释处理有点有限(没有黑客就无法修改现有代码),但它可以做这类事情。或者写一些输出文本的东西。关键是,若你们正在做的工作是可行的,但它太大了,无法手工编写,那个么代码生成就是一种选择。当然,我要说的是Java泛型并不擅长这类事情,当且仅当实现这些接口的每个类都实现了所有这些接口时,这个方案才能可靠地工作而不会出错。在这种情况下,为什么它们是独立的接口?这似乎是一件非常奇怪的事情,而你的匿名样本并没有给出你为什么要这么做的线索。你真正的用例是什么?@yshavit这就是问题的关键所在。这太长了,有没有办法把它变小?如果它更小,那么一开始就不会有问题:P,但是是的,这就是为什么我在给出实现细节之前问这个问题的原因。正如它目前所说的,代码太长,太复杂了,无法在任何一种生产代码中考虑使用。老实说,只要程序员不必编写或维护它,就没有人关心复杂性。如果可以使用注释在幕后生成代码。。。我得调查一下,看看有什么可能。
package test;

public final class Util {

  private Util() {}

  public static AA getStartState() {
    return new AAImpl();
  }
}
package test;

public interface Left<CURRENT_INTERFACE> { }
package test;

public interface Right<CURRENT_INTERFACE> { }
package test;

public interface Combo<CURRENT_INTERFACE> extends 
    Left<CURRENT_INTERFACE>, 
    Right<CURRENT_INTERFACE> { }
package test;

public interface LeftA<CURRENT_INTERFACE> extends Left<CURRENT_INTERFACE> {
  public CURRENT_INTERFACE methodLeftA();
  public <T extends Combo<T> & LeftA<T>> T 
    selectRightType(Selector<T, ?, ?, ?, ?, ?> selector);
}
package test;

public interface LeftB<CURRENT_INTERFACE> extends Left<CURRENT_INTERFACE> {
  public CURRENT_INTERFACE methodLeftB();
  public <T extends Combo<T> & LeftB<T>> T 
    selectRightType(Selector<?, ?, T, ?, ?, ?> selector);
}
package test;

public interface LeftC<CURRENT_INTERFACE> extends Left<CURRENT_INTERFACE> {
  public CURRENT_INTERFACE methodLeftC();
  public <T extends Combo<T> & LeftC<T>> T 
    selectRightType(Selector<?, ?, ?, ?, T, ?> selector);
}
package test;

public interface RightA<CURRENT_INTERFACE> extends Right<CURRENT_INTERFACE> {
  public CURRENT_INTERFACE methodRightA();
  public <T extends Combo<T> & RightA<T>> T 
    selectLeftType(Selector<?, T, ?, ?, ?, ?> selector);
}
package test;

public interface RightB<CURRENT_INTERFACE> extends Right<CURRENT_INTERFACE> {
  public CURRENT_INTERFACE methodRightB();
  public <T extends Combo<T> & RightB<T>> T 
    selectLeftType(Selector<?, ?, ?, T, ?, ?> selector);
}
package test;

public interface RightC<CURRENT_INTERFACE> extends Right<CURRENT_INTERFACE> {
  public CURRENT_INTERFACE methodRightC();
  public <T extends Combo<T> & RightC<T>> T 
    selectLeftType(Selector<?, ?, ?, ?, ?, T> selector);
}
package test;

public interface AA extends Combo<AA>, LeftA<AA>, RightA<AA> { }
package test;

final class AAImpl extends BaseImpl<AA> implements AA {

  @Override
  public <T extends Combo<T> & LeftA<T>> T 
      selectRightType(Selector<T, ?, ?, ?, ?, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftATypeClass());
  }

  @Override
  public <T extends Combo<T> & RightA<T>> T 
      selectLeftType(Selector<?, T, ?, ?, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getRightATypeClass());
  }

}
package test;

public interface AB extends Combo<AB>, LeftA<AB>, RightB<AB> { }
package test;

final class ABImpl extends BaseImpl<AB> implements AB {

  @Override
  public <T extends Combo<T> & LeftA<T>> T 
      selectRightType(Selector<T, ?, ?, ?, ?, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftATypeClass());
  }

  @Override
  public <T extends Combo<T> & RightB<T>> T 
      selectLeftType(Selector<?, ?, ?, T, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getRightBTypeClass());
  }

}
package test;

public interface AC extends Combo<AC>, LeftA<AC>, RightC<AC> { }
package test;

final class ACImpl extends BaseImpl<AC> implements AC {

  @Override
  public <T extends Combo<T> & LeftA<T>> T 
      selectRightType(Selector<T, ?, ?, ?, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getLeftATypeClass());
  }

  @Override
  public <T extends Combo<T> & RightC<T>> T 
      selectLeftType(Selector<?, ?, ?, ?, ?, T> selector) {
    return selectRightTypeBase(selector, selector.getRightCTypeClass());
  }

}
package test;

public interface BA extends Combo<BA>, LeftB<BA>, RightA<BA> { }
package test;

final class BAImpl extends BaseImpl<BA> implements BA {

  @Override
  public <T extends Combo<T> & LeftB<T>> T 
      selectRightType(Selector<?, ?, T, ?, ?, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftBTypeClass());
  }

  @Override
  public <T extends Combo<T> & RightA<T>> T 
      selectLeftType(Selector<?, T, ?, ?, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getRightATypeClass());
  }

}
package test;

public interface BB extends Combo<BB>, LeftB<BB>, RightB<BB> { }
package test;

final class BBImpl extends BaseImpl<BB> implements BB {

  @Override
  public <T extends Combo<T> & LeftB<T>> T 
      selectRightType(Selector<?, ?, T, ?, ?, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftBTypeClass());
  }

  @Override
  public <T extends Combo<T> & RightB<T>> T 
      selectLeftType(Selector<?, ?, ?, T, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getRightBTypeClass());
  }

}
package test;

public interface BC extends Combo<BC>, LeftB<BC>, RightC<BC> { }
package test;

final class BCImpl extends BaseImpl<BC> implements BC {

  @Override
  public <T extends Combo<T> & LeftB<T>> T 
      selectRightType(Selector<?, ?, T, ?, ?, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftBTypeClass());
  }

  @Override
  public <T extends Combo<T> & RightC<T>> T 
      selectLeftType(Selector<?, ?, ?, ?, ?, T> selector) {
    return selectLeftTypeBase(selector, selector.getRightCTypeClass());
  }

}
package test;

public interface CA extends Combo<CA>, LeftC<CA>, RightA<CA> { }
package test;

final class CAImpl extends BaseImpl<CA> implements CA {

  @Override
  public <T extends Combo<T> & LeftC<T>> T 
      selectRightType(Selector<?, ?, ?, ?, T, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftCTypeClass());
  }

  @Override
  public <T extends Combo<T> & RightA<T>> T 
      selectLeftType(Selector<?, T, ?, ?, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getRightATypeClass());
  }

}
package test;

public interface CB extends Combo<CB>, LeftC<CB>, RightB<CB> { }
package test;

final class CBImpl extends BaseImpl<CB> implements CB {

  @Override
  public <T extends Combo<T> & LeftC<T>> T 
      selectRightType(Selector<?, ?, ?, ?, T, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftCTypeClass());
  }

  @Override
  public <T extends Combo<T> & RightB<T>> T 
      selectLeftType(Selector<?, ?, ?, T, ?, ?> selector) {
    return selectLeftTypeBase(selector, selector.getRightBTypeClass());
  }

}
package test;

public interface CC extends Combo<CC>, LeftC<CC>, RightC<CC> { }
package test;

final class CCImpl extends BaseImpl<CC> implements CC {

  @Override
  public <T extends Combo<T> & LeftC<T>> T 
      selectRightType(Selector<?, ?, ?, ?, T, ?> selector) {
    return selectRightTypeBase(selector, selector.getLeftCTypeClass());
  }

  @Override
  public <T extends Combo<T> & RightC<T>> T 
      selectLeftType(Selector<?, ?, ?, ?, ?, T> selector) {
    return selectLeftTypeBase(selector, selector.getRightCTypeClass());
  }

}
import static test.Selector.*;
import static test.Util.*;

public class Main {

  public static void main(String[] args) {
    getStartState()
      .methodLeftA()
      .methodRightA()
      .selectLeftType(B)
      .methodLeftB()
      .methodRightA()
      .selectRightType(B)
      .methodLeftB()
      .methodRightB()
      .selectLeftType(C)
      .methodLeftC()
      .methodRightB()
      .selectRightType(A)
      .methodLeftC()
      .methodRightA()
      .selectLeftType(B)
      .methodLeftB()
      .selectLeftType(A)
      .methodRightA();
  }
}