Это будет работать так, как сейчас, но я считаю плохой концепцией вызывать dispatch () в конце конструктора каждого подкласса.Есть ли более элегантный способ решить эту проблему?Или я должен даже полностью переосмыслить свою концепцию?
Как подчеркнул Тимоти Тракл, ваша логика конструктора слишком сложна.
Вы можете сделать вещи намного проще и достичь своей цели, используя метод шаблона для инициализации экземпляра подкласса.Обратите внимание, что вы уже использовали этот шаблон с doStuff()
.
Конструктор подкласса - действительно ваша проблема: вы хотите уменьшить обязательные котельные плиты, требуемые в каждом подклассе, а также улучшить их читаемость и техническое обслуживание.
Итак, представьтеновый шаблонный метод в суперклассе и вызовите его из конструктора суперкласса.
Этот метод будет делать то же самое, что и конструктор, но его можно вызывать более гибким способом.
dispatch()
, то естьискусственный метод, введенный только для уловки, также не требуется.
Вся логика может быть организована из конструктора суперкласса.
Суперкласс может выглядеть следующим образом:
public abstract class Superclass {
...
public Superclass(...) {
... // do stuff before initializing subclass
init();
doStuff();
}
public abstract void init();
public abstract void doStuff();
}
А в подклассе заменить:
public Subclass(...) {
super(...); //has to be the first line
... //assign variables etc.
dispatch(); //has to be called after variables are assigned etc.
}
на:
public Subclass(...) {
super(...); // let the super constructor to orchestrate the init logic
}
public void init(){
// move the constructor logic here
}
Результат намного проще, потому что этот проект объединяет обязанности, связанные с «алгоритмом» инициализации подкласса в одном месте: конструктор суперкласса.
О вашем комментарии:
Это действительно выглядит более элегантно, чем я.Спасибо!РЕДАКТИРОВАТЬ: только что заметил, это не работает с подклассами, имеющими разные параметры конструктора.Есть идеи, как решить эту проблему?
С таким требованием, чтобы сделать вещи простыми и понятными, вы должны сделать вещи в два этапа:
- создать экземпляр объекта
- вызовите по ссылке метод
init()
.
Это может выглядеть так:
SuperClass o = new Subclass(argFoo, argBar);
o.init();
Проблема с этим способом заключается в том, что вы не уверены, что был вызван метод init()
.Вы можете добавить флаг, который вы проверяете при каждом вызове метода для объекта.Но это действительно громоздко и подвержено ошибкам.Избегайте этого.
Чтобы улучшить это, я бы, вероятно, использовал шаблон оболочки.
Вы также можете использовать перехватчик / аспект.Но это не очень хороший вариант использования: обработка init не является трансверсальной и действительно связана с поведением объекта.Имеет больше смысла держать это видимым.
С оболочкой это может выглядеть следующим образом:
SuperClass o = new MyWrapper(new Subclass(argFoo, argBar));
Где MyWrapper
является подклассом SuperClass
и содержит экземпляр объекта SuperClass
:
public class MyWrapper implements SuperClass{
private SuperClass wrapped;
public MyWrapper (SuperClass wrapped){
this.wrapped = wrapped;
this.wrapped.init();
}
// then delegate each superclass method to the wrapped object
public void doStuff(){
this.wrapped.doStuff();
}
// and so for...
}