Подтвердить что ты не робот

Использование параметра, реализующего несколько интерфейсов

Предположим, что у меня есть эти интерфейсы:

public interface I1 {
  void foo();
}

public interface I2 {
  void bar();
}

и классы:

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
}

Теперь, с generics, у меня может быть такой метод, как:

public <T extends I1 & I2> void method(T param) {
  param.foo();
  param.bar();
}

и я могу назвать его как A, так и B как параметры, но не с C (он не реализует I2).

Был ли способ достижения этого типа предопределенных типов безопасности (java < 1.5).

Учтите, что A, B и C имеют разные деревья наследования, и на самом деле это не совсем так, как AParent и BParent, которые имеют общий родитель.

Я знаю, что вы могли бы сделать:

public void method(I1 param) {
  param.foo();
  ((I2)param).bar();
}

но затем вы также можете вызвать method(new C()), который не реализует I2, поэтому вы попадаете в неприятности.

Итак, есть ли другие способы сделать это?

P.S.: Мне действительно не нужно это делать, это в основном из любопытства, о котором я прошу.

4b9b3361

Ответ 1

Создайте третий интерфейс I3 расширяет I1 и I2. Затем классы A и B реализуют I3, а общий метод принимает I3.

Возможно, это единственный способ сделать это.

Ответ 2

Я не думаю, что выше ответы хороши в дизайне. Когда вы создаете интерфейс, вы хотите удостовериться, что объект-вызов имеет ответственность для некоторых действий, определенных в этом интерфейсе. Таким образом, обсуждаются два решения, и я расскажу, почему эти решения не очень хороши в дизайне.

1. сделать один интерфейс расширяет оба двух интерфейса:

public interface IC extends IA,IB {
   // empty method here
}

Выше код не имеет смысла. Вы определяете отдельный интерфейс, чтобы комбинировать другие интерфейсы, а внутри нет никаких новых методов. Вы не добавляете значение IC вместо объединения двух интерфейсов IA и IB. И в некоторых ситуациях этот способ сделает ваш код "немного веселым", когда вы не сможете найти подходящее имя для третьего интерфейса. Эта ситуация приведет к некоторому имени интерфейса, например IReadableAndWriteable или ISomethingAndSomethingAndAnotherThing

2. тип литой внутри метода:

public void methodA(IA object) {
   if (object instance of IB) {
     ((IB)(object)).someMethod()
}

Этот путь тоже бессмыслен. Почему входной параметр IA, тогда вы должны выполнить какое-либо действие из интерфейса IB? В соответствии с точкой зрения программиста, нет способа узнать это, кроме как от чтения вашего документа. Это плохо для разработки функции для других людей.

Истинное решение:

В решениях есть еще одна проблема в дизайне: программист force использует один объект, несущий ответственность за два интерфейса. В чем проблема, если программист не хочет этого делать. Они хотят использовать два разных бетонных класса для разных интерфейсов для более простого тестирования, чистого кода? Они не могут.

В вашей сигнатуре метода вы должны сделать два разных параметра:

public void exampleMethod(IA object1, IB object2) {
   object1.someMethod()
   object2.someMethod()
}

И для вызова метода выше вы вводите один и тот же параметр внутри (если программист использует тот же объект). Они также могут помещать разные объекты.

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);       
}

Надеюсь, что эта помощь:)

Ответ 3

До версии Java 1.5 в IMO нет решения для достижения такой секретности типа во время компиляции. Но во время исполнения есть душа, используя "экземпляр".

public void method(Object o) {
  if (!(o instanceof I1))
    throw new RuntimeException("o is not instance of I1");

  if (!(o instanceof I2))
    throw new RuntimeException("o is not instance of I2");

  // go ahead ...
}

Ответ 4

sri - лучший ответ, если у вас есть разрешение на изменение подписи A и B. Однако если у вас не было разрешения, вы могли бы сделать:

public void method(I1 param1 , I2 param2) { // unpopular classes that do not implement I3 must use this method
  param1.foo();
  param2.bar();
}
public void method(I3 param){ // I hope everybody implements I3 when appropriate
  param.foo();
  param.bar();
}
public void method(A param){// A is a popular class
  method(param,param);
}
public void method(B param){// B is a popular class
  method(param,param);
}

Конечно, теперь просто используйте generics.