лучшие практики / шаблоны проектирования, кроме перегрузки конструктора java

У меня есть класс с несколькими конструкторами. Каждый представляет разные варианты использования.

public class ABC {
  public ABC(int x) {
  ...
  }
  public ABC(ArrayList<String> Stringarray) {
  ...
  }
  ..many more constructors..
}

До сих пор перегрузка конструктора была чистым решением, пока я не столкнулся с такими же проблемами стирания из компилятора java. Например, я хочу добавить еще один конструктор, который в конечном итоге будет иметь такое же стирание, поэтому я просто решил включить параметр по умолчанию, чтобы обойти его сейчас, как показано ниже:

public ABC(ArrayList<String> stringArray) {
  …
}
public ABC(ArrayList<Integer> integerArray, boolean… sameErasureFlag) {
  …
}

Но у меня есть сильное предчувствие, что, вероятно, наличие такого количества конструкторов не является хорошим шаблоном проектирования для этого варианта использования ... Может быть, есть лучшее решение или шаблон проектирования передовой практики, который используется для такого сценария. Я ищу образец строителя, но не уверен, что он правильный / лучший. Есть рекомендации?


comment
Вам действительно нужно предоставить больше информации о фактическом варианте использования, потому что сейчас похоже, что вы пытаетесь создать класс бога вместо того, чтобы сохранять свой класс простым и заставлять их делать только одно. Рассматривали ли вы универсальные шаблоны с использованием интерфейса и соответствующих абстракций?   -  person Mark Rotteveel    schedule 19.03.2021


Ответы (6)


У меня есть класс с несколькими конструкторами. Каждый из них представляет разные варианты использования.

Тогда простой ответ: превратите каждый вариант использования в отдельный класс.

Идея о том, что у вас есть несколько несвязанных полей в классе, и каждый вариант использования использует только некоторые из них, является четким указанием на то, что ваш класс делает слишком много вещей. .

Любой класс или метод должны делать только одно. Итак, как уже было сказано: ответ - остановиться прямо здесь и вместо того, чтобы добавлять больше вещей в один класс: спросите себя, как вы могли бы осмысленно разорвать его на части.

person GhostCat    schedule 19.03.2021
comment
Предположим, вы имеете в виду Боба Мартина: метод должен делать только одно. Класс - это другая область видимости. Насколько мне известно, он никогда не предлагал классу делать что-то одно. Наоборот. - person jaco0646; 19.03.2021
comment
Я не согласен. Объем класса по-прежнему должен быть одним. Просто в большем объеме. В идеале все ваши методы используют все ваши поля. Как только вы можете рисовать четкие линии и x / y / z используется только foo () / bar (), а a / b / c используется horr () / ible (), это явный признак того, что ваш класс делает две вещи и должен быть разорван на части. - person GhostCat; 19.03.2021
comment
Чтобы было ясно, приписываете ли вы эту точку зрения Бобу Мартину или это ваше личное мнение? - person jaco0646; 19.03.2021
comment
Мартин - решительный сторонник принципа единственной ответственности. Вы думаете, что это относится только к методам? - person GhostCat; 20.03.2021
comment
Мартин создал SRP; но он отделен от чего-то одного и не связан с ним. Это (распространенная) путаница, рассмотренная в ссылке в моем первом комментарии выше. - person jaco0646; 20.03.2021
comment
Убедительные аргументы, но я думаю, что Мартин довольно сильно подчеркивает одну идею в одном из своих многочисленных видеоуроков (некоторые из них были записаны годами позже). Но их так много, что мне было бы трудно ее найти. - person GhostCat; 21.03.2021
comment
Описания Мартином SRP, безусловно, развивались и совершенствовались с годами. С одной стороны, я ценю его стремление учиться и совершенствоваться. С другой стороны, я думаю, что большая часть путаницы вокруг SRP создана им самим. В научных исследованиях принято, что новые публикации уточняют и исправляют старые. По этой причине я считаю, что лучший (и самый простой) подход - рассматривать более позднюю работу как замену предыдущей. - person jaco0646; 22.03.2021
comment
Текущая позиция Мартина (по крайней мере с 2014 года) заключается в том, что SRP касается людей (а не вещей). Буквально на прошлой неделе он поддержал эту ветку твиттера с той же точки зрения. - person jaco0646; 22.03.2021

Действительно ли ваш класс реализует разные варианты использования, каждый из которых представлен другим конструктором? Тогда это ответ!

Если вы просто хотите предоставить разные пути инициализации для вашего класса, который в остальном делает то же самое, независимо от формата данных, которые вы использовали для инициализации, то наличие нескольких конструкторов может быть правильным.

Но при превышении определенного количества конструкторов (одни говорят 3, другие 5 ... некоторые экстремисты говорят даже 1) их определенно слишком много, и тогда вам следует рассмотреть фабричный шаблон, как предлагается здесь. Это следует обязательно учитывать - независимо от того, сколько у вас конструкторов - когда вы думаете о введении «фиктивных» параметров для решения проблем со стиранием. Преимущество фабричного шаблона в том, что сигнатура фабричного метода определяется не только списком параметров, вы также можете выбрать другое имя (ABC.ofIntList(), ABC.ofStringList() и так далее…).

person tquadrat    schedule 19.03.2021

Это зависит от того, что именно класс делает с параметрами, у нас нет точных деталей, но одна простая вещь, которую вы можете сделать для универсальных типов, - это сделать свой собственный класс универсальным (и, возможно, нет необходимости применять причудливый шаблон проектирования. в этом случае):

public class ABC<T> {
    public ABC(ArrayList<T> stringArray) {
       …
    }
    …
}


ArrayList<Integer> intList = Stream.of(1, 2, 3)
                                   .collect(Collectors.toCollection(ArrayList::new));
ArrayList<String> stringList = Stream.of("a", "b", "c")
                                   .collect(Collectors.toCollection(ArrayList::new));
ABC<Integer> abc1 = new ABC<>(intList);
ABC<String> abc2 = new ABC<>(stringList);
person M A    schedule 19.03.2021
comment
но это не поможет мне с проблемой стирания, если я хочу иметь ArrayList разных типов, как указано в вопросе. - person drk; 19.03.2021
comment
@drk Я обновил информацию о том, как его использовать. Дело в том, что во время компиляции аргумент типа может использоваться компилятором для определения правильного типа списка. Конечно, во время выполнения стирание все еще существует (тип заменяется на Object). Вы также можете создавать подклассы ABC<T> с правильным аргументом типа (например, class ABCString extends ABC<String>). - person M A; 22.03.2021

У меня есть сильное предчувствие, что, вероятно, наличие такого количества конструкторов - не лучший шаблон дизайна.

Это зависит.

Некоторые люди предпочитают конструкторы, некоторые - другие подходы, но я думаю, что вы правы, что наличие большого количества перегруженных конструкторов может быть громоздким для чтения и обслуживания.

Одной из альтернатив, которую следует рассмотреть, является Static Factory Methods. В последнее время многие авторы предлагают отдавать предпочтение статическим фабричным методам конструкторам.

Есть несколько причин, по которым вы можете захотеть отдать им предпочтение:

Они обеспечивают лучшую, понятную и интуитивно понятную читаемость.

Вы не можете давать имена конструкторам. Имя конструктора всегда совпадает с именем класса; однако вы можете найти полезным использовать именование, так как они обеспечат более четкую читаемость.

Вы можете создавать и возвращать подтипы

Когда вы используете конструктор, вы не можете изменять тип создаваемого объекта; однако фабричный метод может возвращать объект s, производный от суперкласса, что означает, что вы можете решить, что именно создавать, в зависимости от входных критериев.

person Giorgi Tsiklauri    schedule 19.03.2021

Если в вашем классе слишком много полей, я бы посоветовал вам плохой дизайн. Некоторые могут посоветовать использовать Шаблон Строителя. Но я думаю, что лучше проявлять больше уважения к ООП, поэтому я думаю, что лучше разбить свой класс на несколько классов и использовать Шаблон декоратора.

person Cristian    schedule 19.03.2021

Да, наличие большого количества конструкторов может указать на то, что класс нарушает принцип единой ответственности. Согласен - информации недостаточно для принятия решения. Строитель может работать по шаблону или даже по абстрактной фабрике. Однако - рассмотрите возможность использования фабричного метода вместо конструкторов, как посоветовал Дж. Блох:

public ABC of(ArrayList<Integer> integerArray, boolean… sameErasureFlag) {

… }

person Olena Dirych    schedule 19.03.2021