Конструкторы могут быть перегружены, как и любой другой метод, и я знаю об этом. В связи с задачей я решил использовать абстрактный суперкласс с несколькими конструкторами:
Абстрактный суперкласс:
protected ListSortierer()
{
this( null, null );
}
protected ListSortierer( List<E> li )
{
this( li, null );
}
protected ListSortierer( Comparator<E> comp )
{
this( null, comp );
}
protected ListSortierer( List<E> li, Comparator<E> com )
{
this.original = Optional.ofNullable( li );
this.comp = Optional.ofNullable( com );
}
Для доступа к каждому из этих конструкторов мне также потребовалось несколько конструкторов в подклассе.
BubbleSort.java:
public ListBubbleSort()
{
super();
}
public ListBubbleSort( List<E> li )
{
super( li );
}
public ListBubbleSort( Comparator<E> com )
{
super( com );
}
public ListBubbleSort( List<E> li, Comparator<E> com )
{
super( li, com );
}
В этом случае каждый конструктор подкласса немедленно вызывает конструктор суперкласса. Мне пришло в голову, что я мог бы снова обратиться к собственному конструктору и передать значения null:
public ListBubbleSort()
{
this( null, null );
}
public ListBubbleSort( List<E> li )
{
this( li, null );
}
public ListBubbleSort( Comparator<E> com )
{
this( null, com );
}
public ListBubbleSort( List<E> li, Comparator<E> com )
{
super( li, com );
}
Это позволило бы мне опустить 3 перегруженных конструктора в абстрактном суперклассе, но потребовало бы, чтобы каждый подкласс следовал одному и тому же шаблону.
Мой вопрос: какой подход лучше в случае согласованности? Обрабатывать отсутствующие значения в абстрактном суперклассе или в подклассе? Имеет ли значение создание экземпляров или это просто вопрос мнения?
ИМО, я бы выбрал более строгий в суперклассе (требующий двух аргументов), и подкласс может либо следовать за тем же, либо может предоставить один arg-конструктор, который делегирует, передавая null для остальных
Мой совет - использовать шаблон Builder, который создает для вас экземпляр ListBubbleSort.
Конечно, хорошая практика будет заключаться в том, чтобы код был правильно отформатирован в соответствии с соглашением Java. { должен быть в той же строке, что и имя метода. Кроме этого, приятного поста, но я думаю, что он слишком широкий, будет лучше задать вопрос обзор кода, если вы это сделаете, тогда удалите пост там, чтобы предотвратить публикацию междоменного сообщения.
@xxxvodnikxxx, возможно, вы правы, что этот вопрос также подходит для Проверка кода, но я явно хотел знать, есть ли какие-либо технические эффекты, касающиеся создания экземпляра. А по поводу условностей. Это не только стиль моей компании, но и так называемый Конвенция Оллмана, который нередко используется в java.
Остерегайтесь использования словосочетания «передовой опыт»: Satisfice.com/blog/archives/27, Innovationexcellence.com/blog/2013/03/09/…, forbes.com/sites/mikemyatt/2012/08/15/best-practices-arent.
просто примечание, что вы собираетесь делать с пустым списком? Поэтому я бы для начала установил ненулевой список ...
@ Евгений. Обычно, если списка нет, конкретный алгоритм, реализованный в подклассе, получает пустой список, и поэтому результат также будет пустым списком.
Итак, оказывается, что ни один из ваших аргументов не требуется ... в таком случае шаблон строителя - это то, что вам нужно
Есть ли что-нибудь против использования только двухпараметрического ctor, а затем позволить вызывающему коду предоставлять new List<E>() (или null для Comparator<E>), если это то, что там нужно? Вызов конструктора таким образом тоже должен уместиться в одну строку.
@ R.Schmitz, но это не сделало бы этот вопрос настолько популярным :)
@StephenC Сильно не согласен. В любом случае, две опубликованные вами статьи, похоже, в значительной степени нападают на соломенного человека.
Этот вопрос принадлежит codereview.stackexchange.com




Doing so would allow me to omit 3 of the overloaded constructors in the abstract superclass but would enforce that every subclass follows the same pattern.
Обеспечение выполнения контракта достигается с помощью абстрактных методов или интерфейсов. Вы не можете быть уверены, что каждый подкласс будет иметь эти конструкторы, или, по крайней мере, вы не можете быть уверены, что каждый подкласс будет правильно добавлять эти конструкторы.
Итак, учитывая Инкапсуляция, эти конструкторы лучше подходят для суперкласса.
Что касается самого вопроса: я думаю, что оба варианта не идеальны.
Вы стремитесь писать как можно меньше кода. Вы осторожны при добавлении перегрузок только потому, что они кажутся удобный. На самом деле, вам следует сделать обратное: как следует подумать, какие у вас варианты использования настоящий, и поддерживать только их.
И в вашем случае весь смысл упражнения, похоже, состоит в том, чтобы разрешить сортировку с разными реализациями. И в этом смысле вам лучше посмотреть, например, на шаблон стратегии.
Другими словами: ваша мысль первый всегда предпочитать композицию наследованию. И когда ваш дизайн приводит вас к таким вопросам, ответ лучше может заключаться в том, чтобы отступить от вашего текущего дизайна и найти способ включить различную сортировку в качестве некой «службы» - вместо того, чтобы объединять сам список в единое целое для сортировки.
What is a better approach in case of consistency?
Представьте статические фабричные методы.
ListBubbleSort.withList(List<E> list)
ListBubbleSort.withComparator(Comparator<E> comparator)
Выполните вызов подходящего конструктора super. Не проходите мимо null.
public static <E> ListBubbleSort withList(List<E> list) {
return new ListBubbleSort(list);
}
private ListBubbleSort(List<E>) {
super(list);
}
protected ListSortierer(List<E>) {
// initialise only the list field
this.origin = list;
}
Не используйте Optional как поле.
this.original = Optional.ofNullable(li);
Рассмотрим Шаблон Строителя, если у вас 3+ параметра.
Handle missing values in the abstract superclass or in the subclass?
Конструктор должен предоставить начальные значения. Вы не передаете начальные значения, вы просто указание на их отсутствие.
По умолчанию null является начальным значением для ссылочных типов. Таким образом, нет необходимости переназначать поле, если для него не было задано значение.
Does it make a difference regarding instantiation or is it just a matter of opinion?
Читаемость, обслуживание.
Я бы порекомендовал прочитать Эффективная Java от Джошуа Блоха:
Создание и уничтожение объектов
Вы можете добавить последний addAll, который будет вызываться в дочерних конструкторах в качестве необязательного дополнения. Для компаратора семантика различается, он (почти) должен быть перегружен, когда это необязательно.
private final Optional<Comparator<E>> comparatorOption;
public final void addAll(List<E> li) {
...;
}
protected ListSortierer() {
comparatorOption = Optional.empty();
}
protected ListSortierer(Comparator<E> comp) {
comparatorOption = Optional.of(comp);
}
Лучше избегать нулевых параметров.
Если вы хотите, чтобы все подклассы имели одни и те же конструкторы, имея много конструкторов, это неплохо. Преимущество в том, что API для всех классов ведут себя одинаково. Однако это ненужный код котельной плиты, который может предотвратить шаблон строителя. В первоначальной старой java использовалось множество конструкторов, но в настоящее время можно встретить множество конструкторов в API.
Для сортировщика списков идеальной идеей может быть свободный API с использованием какого-либо конструктора.
Итак, окончательный ответ: решение в большей степени зависит от стиля.
Doing so would allow me to omit 3 of the overloaded constructors in the abstract superclass but would enforce that every subclass follows the same pattern.
Подкласс не имеет ограничений для вызова определенного конструктора родительского класса. Он может вызывать любой из них, в то время как это вызывает один из них. Значит, вы не смогли добиться такого требования.
Что касается решения с использованием метода статической фабрики, в некоторых случаях это приемлемо и даже нормально, но это не чудо и также имеет некоторые ограничения. Например: не позволяет переходить на другие реализации. Я согласен с тем, что для классов JDK это почти никогда не проблема, но для пользовательского класса мы должны использовать его с осторожностью. Кроме того, ничто не мешает подклассу расширять родительский класс и не проходить мимо фабрики для создания экземпляров этого подкласса. Таким образом, указанное требование также не обеспечивается.
My question is: What is the the better approach in case of consistency?Handle missing values in the abstract superclass or in the subclass? Does it make a difference regarding instantiation or is it just a matter of opinion?
Это не вопрос мнения. Это имеет значение. Если подкласс делегирует родительский класс и проверки всегда одинаковы, кажется интересным позволить родительскому классу выполнять проверки. Но если у вас нет гарантии, что родительский класс никогда не будет изменен в отношении проверок, подклассы могут создать некоторые экземпляры несогласованности, если родительский класс изменит свои проверки.
В последнем блоке вашего ответа есть действительно сильная сторона, которую я еще не рассмотрел. Спасибо за понимание!
Конечно, это субъективное мнение. С точки зрения чистого кода и отсутствия ненужного дублирования в суперклассе должен быть только один конструктор. В любом случае вам понадобится несколько конструкторов в подклассе, а суперкласс не может быть создан клиентским кодом напрямую.