Как интерфейс может включать метод, который ссылается на конкретный тип реализации интерфейса в его сигнатуре или возвращаемом типе?

Предположим, я разрабатываю что-то вроде следующего интерфейса:

public interface MyInterface{
  public MyInterface method1();
  public void method2(MyInterface mi);
}

Однако есть предостережение, что возвращаемый тип для method1 и параметр для method2 соответствуют конкретной реализации, а не только MyInterface .То есть, если у меня есть MyInterfaceImpl , который реализует MyInterface , он должен иметь следующее:

public class MyInterfaceImpl implements MyInterface{
  @Override
  public MyInterfaceImpl method1(){...}

  @Override
  public void method2(MyInterfaceImpl mi){...}
}

Как написано выше, method1 не приведет к компиляции ошибок, но нет никакой гарантии, что тип возвращаемого значения соответствует во всех реализациях. Конечно, method2 даже не будет компилироваться, потому что подпись не соответствует интерфейсу.

Одним из возможных решений является использование самореференциальных или рекурсивных границ в дженериках:

public interface MyInterface<T extends MyInterface<T>>{
  public T method1();
  public void method2(T mi);
}

public class MyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
  @Override
  public MyInterfaceImpl method1();

  @Override
  public void method2(MyInterfaceImpl mi);
}

Это даст мне то, что я хочу, за одним исключением: другие реализации могут передать неправильный общий тип (ничто не заставляет T в соответствии с типом бетона). Так что потенциально кто-то другой может реализовать следующее:

public class NotMyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
  @Override
  public MyInterfaceImpl method1();

  @Override
  public void method2(MyInterfaceImpl mi);
} 

Это будет хорошо скомпилировано, хотя NotMyInterfaceImpl должен реализовать MyInterface . * Это заставляет меня думать, что мне что-то нужно еще.

* Обратите внимание: я не думаю, что пытаюсь нарушить LSP; Я согласен с тем, что тип / параметр возвращаемого значения являются подклассами NotMyInterfaceImpl .

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

14
задан Michael McGowan 29 September 2011 в 22:21
поделиться