Я хочу, чтобы функция возвращала экземпляр подкласса, из которого она была вызвана - PullRequest
1 голос
/ 05 мая 2010

Я хочу иметь функцию, определенную в суперклассе, которая возвращает экземпляр подкласса, который используется для вызова функции. То есть, скажем, у меня есть класс A с функцией plugh. Затем я создаю подклассы B и C, которые расширяют A. Я хочу, чтобы B.plugh возвращал B, а C.plugh возвращал C. Да, они могли возвращать A, но тогда вызывающий должен был бы либо привести его вправо подтип, который вызывает боль при частом использовании или объявляет принимающую переменную как супертип, что теряет безопасность типа.

Итак, я пытался сделать это с помощью дженериков, написав что-то вроде этого:

class A<T extends A>
{
  private T foo;
  public T getFoo()
  {
    return foo;
  }
}
class B extends A<B>
{
  public void calcFoo()
  {
    foo=... whatever ...
  } 
}
class C extends A<C>
{
   public void calcFoo()
  {
    foo=... whatever ...
  } 
}

Кажется, это работает, но выглядит довольно уродливо.

Во-первых, я получаю предупреждения class A<T extends A>. Компилятор говорит, что A является универсальным, и я должен указать тип. Я думаю, что он хочет, чтобы я сказал class A<T extends A<x>. Но что бы я положил на х? Я думаю, что могу застрять здесь в бесконечном цикле.

Кажется странным писать class B extends A<B>, но это не вызывает никаких нареканий, так что, может быть, это нормально.

Это правильный способ сделать это? Есть ли лучший способ?

Ответы [ 2 ]

1 голос
/ 05 мая 2010
class A<T extends A<T>> {

Или я предпочитаю:

class A<THIS extends A<THIS>> {

Как java.lang.Enum. Унифицирует клиентский код, который просто хочет A, но должен написать A<?>.

Обратите внимание, что это никоим образом не нарушает LSP и является ХОРОШИМ.

Или вы можете просто использовать ковариантные типы возвращаемых данных.

0 голосов
/ 05 мая 2010

Делать это, с точки зрения ОО, очень плохая вещь & trade ;. Это нарушает принцип подстановки Лискова для одного - если B & C оба являются A, то B.getFoo () и C.getFoo () должны возвращать одно и то же - что в этом случае они не будут. Если вызывающий должен знать, что он получает при вызове метода, есть большая вероятность, что ваша иерархия наследования неверна.

...