使用实现多个接口pre-generics的参数

And*_*anu 35 java generics parameters multiple-inheritance

假设我有这些接口:

public interface I1 {
  void foo();
}

public interface I2 {
  void bar();
}
Run Code Online (Sandbox Code Playgroud)

和班级:

public class A extends AParent implements I1, I2 {
   // code for foo and bar methods here
}

public class B extends BParent implements I1, I2 {
  // code for foo and bar methods here
}

public class C extends CParent implements I1 {
  // code for foo method here
}
Run Code Online (Sandbox Code Playgroud)

现在,使用泛型我可以有一个方法,如:

public <T extends I1 & I2> void method(T param) {
  param.foo();
  param.bar();
}
Run Code Online (Sandbox Code Playgroud)

我可以用A和B作为参数调用它,但不能用C调用它(它不实现I2).

有没有办法实现这种类型的安全预先通用(java <1.5).

考虑到A,B和C具有不同的继承树,并且实际上不能选择像父母一样拥有共同父级的AParent和BParent.

我知道你可以这样做:

public void method(I1 param) {
  param.foo();
  ((I2)param).bar();
}
Run Code Online (Sandbox Code Playgroud)

但是你也可以调用method(new C())哪个没有实现I2,所以你遇到了麻烦.

那么你有没有其他方法可以做到这一点?

PS:我真的不需要这样做,这主要是出于好奇,我问.

Sri*_*nan 26

创建第三个接口I3扩展I1和I2.然后A类和B类都实现I3,泛型方法接受I3.

这可能是唯一的方法.

  • 在我提出这个问题之后,我有点意识到这一点,但是如果你有两个以上的接口,并且你想混合和匹配不同方法的接口,那么为你想要使用的每个组合创建一个子接口可能会很麻烦.我更多地考虑使用像`method(I1&I2 param)`这样的方法或者其他方式来说这个参数实现了多个接口(没有创建新的类/接口) (5认同)

hqt*_*hqt 12

我不认为上述答案在设计观点下是好的.在创建接口时,您希望确保调用者对象对该接口中定义的某些操作负责.所以上面讨论了两种解决方案,我将告诉为什么这些解决方案在设计方面并不好.

1.使一个接口扩展到两个接口:

public interface IC extends IA,IB {
   // empty method here
}
Run Code Online (Sandbox Code Playgroud)

上面的代码是无意义的.您只需要组合一个单独的接口来组合其他接口,并且内部没有任何新方法.您不添加任何值,IC而不是组合两个接口IAIB.在某些情况下,当您找不到第三个界面的合适名称时,这种方式会使您的代码"变得有趣".这种情况会导致一些接口名称,如IReadableAndWriteableISomethingAndSomethingAndAnotherThing

2.类型转换内部方法:

public void methodA(IA object) {
   if (object instance of IB) {
     ((IB)(object)).someMethod()
}
Run Code Online (Sandbox Code Playgroud)

这种方式也是无稽之谈.为什么输入参数是IA必须从接口执行某些操作IB?在程序员的观点下,除了阅读你的文档之外,没有办法知道这一点.这对于设计其他人使用的功能并不好.

真正的解决方

以上解决方案在设计中存在另一个问题:您强制程序员使用一个负责两个接口的对象.如果程序员不想这样做会有什么问题.他们想为每个不同的接口使用两个不同的混凝土类,以便于测试,清洁代码?他们不能.

您应该在方法签名中创建两个不同的参数:

public void exampleMethod(IA object1, IB object2) {
   object1.someMethod()
   object2.someMethod()
}
Run Code Online (Sandbox Code Playgroud)

并且为了调用上面的方法,你将相同的参数放在里面(如果程序员使用相同的对象).他们也可以放置不同的物品.

public void caller() {
   IC object3 = new C(); // C is the class implements both IA and IB
   exampleMethod(object3, object3);
   IA objectA = new A();
   IB objectB = new B();
   exampleMethod(objectA, objectB);       
}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助:)

  • 对不起,我唤醒了一个老话题,但我认为这是值得的.我真的认为这个答案是最好的.然而,对于第1点而言,它是否有意义是相当主观的(至少可以作为一种临时解决方案),但是有一个非常客观和实际的案例表明它不是一个好的设计:如果你实现了一个扩展相关接口的类,但*不是*组合它们的接口,那么你不能在一个要求组合接口的方法中使用它,尽管它尊重初始合同. (2认同)
  • 我无法编辑先前的答案,因此我添加了另一个答案:组合界面的想法要么不好,要么不完整。它不应该只是一个接口,而应该是一个包装器:如果您是从外部库获取实现的,但是希望这两个接口的任何实现都可用,那么您也不希望受到lib的限制,那么您需要包装器或适配器(如果需要)。此解决方案可确保您实际上具有与同一实例相关联的两个接口,而以上hqt的帖子不允许确保此类约束,这仍然值得。 (2认同)