У меня есть иерархия объектов, которая усложняется по мере углубления дерева наследования. Ни один из них не является абстрактным, следовательно, все их экземпляры служат более или менее сложной цели.
Поскольку количество параметров достаточно велико, я бы хотел использовать шаблон Builder для установки свойств, а не кодировать несколько конструкторов. Поскольку мне нужно удовлетворить все перестановки, листовые классы в моем дереве наследования будут иметь телескопические конструкторы.
Я искал ответ здесь, когда столкнулся с некоторыми проблемами во время моего дизайна. Прежде всего, позвольте мне привести простой, поверхностный пример, иллюстрирующий проблему.
public class Rabbit
{
public String sex;
public String name;
public Rabbit(Builder builder)
{
sex = builder.sex;
name = builder.name;
}
public static class Builder
{
protected String sex;
protected String name;
public Builder() { }
public Builder sex(String sex)
{
this.sex = sex;
return this;
}
public Builder name(String name)
{
this.name = name;
return this;
}
public Rabbit build()
{
return new Rabbit(this);
}
}
}
public class Lop extends Rabbit
{
public float earLength;
public String furColour;
public Lop(LopBuilder builder)
{
super(builder);
this.earLength = builder.earLength;
this.furColour = builder.furColour;
}
public static class LopBuilder extends Rabbit.Builder
{
protected float earLength;
protected String furColour;
public LopBuilder() { }
public Builder earLength(float length)
{
this.earLength = length;
return this;
}
public Builder furColour(String colour)
{
this.furColour = colour;
return this;
}
public Lop build()
{
return new Lop(this);
}
}
}
Теперь, когда у нас есть код для продолжения, я хочу построить Lop
:
Lop lop = new Lop.LopBuilder().furColour("Gray").name("Rabbit").earLength(4.6f);
Этот вызов не будет компилироваться, так как последний цепочечный вызов не может быть решен, при этом Builder
не определяет метод earLength
. Таким образом, этот способ требует, чтобы все вызовы были связаны в определенном порядке, что очень непрактично, особенно с глубоким иерархическим деревом.
Теперь, во время поиска ответа, я натолкнулся на создание подкласса класса Java Builder, в котором предлагается использовать шаблон Curiously Recursive Generic. Однако, поскольку моя иерархия не содержит абстрактный класс, это решение не будет работать для меня. Но подход основан на абстракции и полиморфизме, поэтому я не верю, что смогу адаптировать его к своим потребностям.
Подход, который я сейчас выбрал, состоит в том, чтобы переопределить все методы Builder
суперкласса в иерархии и просто сделать следующее:
public ConcreteBuilder someOverridenMethod(Object someParameter)
{
super(someParameter);
return this;
}
При таком подходе я могу заверить меня, что мне возвращают экземпляр, на котором я могу выполнять цепные вызовы. Хотя это и не так плохо, как "Телескопический анти-паттерн", это вторая секунда, и я считаю это немного "хакерским".
Есть ли другое решение моей проблемы, о котором я не знаю? Желательно, чтобы решение соответствовало шаблону дизайна. Спасибо!