Java: возвращающий подкласс в подклассе метода суперкласса - программирование
Подтвердить что ты не робот

Java: возвращающий подкласс в подклассе метода суперкласса

Я работаю над проблемой, где есть несколько реализаций Foo, сопровождаемых несколькими FooBuilder. В то время как Foo разделяет несколько общих переменных, которые необходимо установить, они также имеют разные переменные, для которых требуется соответствующее FooBuilder реализовать некоторые конкретные функции. Для лаконичности я хотел бы, чтобы сеттеры FooBuilder использовали цепочку методов, например:

public abstract class FooBuilder {
  ...

  public FooBuilder setA(int A) {
    this.A = A;
    return this;
  }

  ...
}

и

public class FooImplBuilder extends FooBuilder{
  ...
  public FooImplBuilder setB(int B) {
    this.B = B;
    return this;
  }
  public FooImplBuilder setC(int C) {
    this.C = C;
    return this;
  }
  ...
}

И так далее, с несколькими различными реализациями FooBuilder. Это технически делает все, что я хочу, однако этот подход чувствителен к порядку вызова методов при выполнении цепочки методов. Ниже приведен метод undefined ошибки компиляции:

someFoo.setA(a).setB(b)...

Требование, чтобы разработчик думал о порядке вызовов методов в цепочке. Чтобы этого избежать, я хотел бы, чтобы сеттеры в FooBuilder каким-то образом возвращали фактический исполняемый подкласс. Однако я не уверен, как это сделать. Каков наилучший подход?

4b9b3361

Ответ 1

Это хороший вопрос и реальная проблема.

Самый простой способ справиться с этим в Java, вероятно, предполагает использование дженериков, как указано в ответе Йохена.

Хорошее обсуждение проблемы и разумное решение в этой записи в блоге Использование Наследования с Свободными Интерфейсами, в котором сочетаются общие понятия с определением метода getThis() переопределить в подклассах строителя, чтобы решить проблему всегда возврата строителя правильного класса.

Ответ 2

Здесь может быть полезен дженерик.

Если вы объявите setA() что-то вроде этого (псевдокод)

<T> T setA(int a)

компилятор должен иметь возможность определять реальные типы, и если это не так, вы можете дать подсказки в коде, например

obj.<RealFoo>setA(42)

Ответ 3

Найдя этот отличный ответ, теперь я расскажу о нем.

public class SuperClass<I extends SuperClass>
{
    @SuppressWarnings( "unchecked" ) // If you're annoyed by Lint.
    public I doStuff( Object withThings )
    {
        // Do stuff with things.
        return (I)this ; // Will always cast to the subclass. Causes the Lint warning.
    }
}

public class ImplementationOne
extends SuperClass<ImplementationOne>
{} // doStuff() will return an instance of ImplementationOne

public class ImplementationTwo
extends SuperClass<ImplementationTwo>
{} // doStuff() will return an instance of ImplementationTwo