Конструктор Java с большими спорами или бобовым подходом метода get/метода set Java

Другая вещь рассмотреть в старом синтаксисе соединения, это, очень легко получить соединение cartesion случайно, так как существует не на пункте. Если Отличное ключевое слово находится в запросе, и это использует старые соединения стиля, преобразуйте, это к стандарту ANSI присоединяется и видит, нужно ли Вам все еще отличное. При фиксации случайных соединений cartesion этот путь можно улучшить производительность чрезвычайно путем перезаписи для определения соединения и объединяющих полей.

26
задан deelo55 27 October 2009 в 17:22
поделиться

18 ответов

Лучший подход (imho) - использовать какой-нибудь конструктор:

MyClass a = new MyClassBuilder().blah("blah").foo("foo").doStuff().toMyClass();

где MyClass по-прежнему неизменяемый , но его создание гораздо более читабельно, чем конструктор с 10 аргументы.

Это также называется свободным интерфейсом . Джош Блох ссылается на это в Эффективная Java .

31
ответ дан 28 November 2019 в 06:02
поделиться

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

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

0
ответ дан 28 November 2019 в 06:02
поделиться

Существуют ли варианты класса, которые могут занять меньше аргументы, или есть только один и десять свойств?

Является ли объект неизменным?

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

1
ответ дан 28 November 2019 в 06:02
поделиться

Можно ли объединить ваши поля в промежуточный объект? Например, если вы передаете 10 полей, описывающих человека, создайте объект PersonInfo для передачи этих данных. Я лично предпочитаю передавать все обязательные поля при создании экземпляра объекта. Таким образом, вы не получите недоделанный предмет, которым неизбежно будут злоупотреблять.

0
ответ дан 28 November 2019 в 06:02
поделиться

Если все параметры на самом деле являются обязательными, тогда Я не вижу причин, почему бы не использовать конструктор. Однако, если это не так, то лучшим подходом будет использование компоновщика.
На мой взгляд, наихудшее решение - полагаться только на сеттеры, поскольку нет ничего, что могло бы заставить установить все обязательные свойства. Конечно, если вы используете соединение bean-компонентов Spring Framework или другое подобное решение, то Java-bean-компоненты вполне подойдут, так как вы можете проверить после инициализации, что все было установлено.

1
ответ дан 28 November 2019 в 06:02
поделиться

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

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

2
ответ дан 28 November 2019 в 06:02
поделиться

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

Widget widge = new Widget.Builder(). manufacturer("333").serialNumber("54321").build();
4
ответ дан 28 November 2019 в 06:02
поделиться

На самом деле зависит от конкретного класса. Должен ли он быть неизменным? Это простой объект-значение без какого-либо поведения? Собираетесь ли вы сопоставить этот объект значения с параметрами веб-службы или с реляционной базой данных? Вы собираетесь сериализовать его? (Некоторым из этих вещей нужен конструктор по умолчанию). Не могли бы вы рассказать об объекте подробнее?

1
ответ дан 28 November 2019 в 06:02
поделиться

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

Связаны ли некоторые из этих полей / параметров? Могут ли они быть объединены в объекты, которые имеют смысл (например, координата x и координата y , объединенные в объект Point и т. Д.)

27
ответ дан 28 November 2019 в 06:02
поделиться

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

OP был обновлен, чтобы отклонить шаблон построителя, но, похоже, это основано на недоразумении. Тот факт, что существует шаблон Builder, не отменяет принудительное применение всех параметров.

Рассмотрим следующий объект:

 public class SomeImmutableObject {
      private String requiredParam1;
      private String requiredParam2;
      //etc.

      private SomeImmutableObject() { //cannot be instantiated outside the class }

      public static class Builder {
          private SomeImmutableObject instance;
          public Builder() { instance = new SomeImmutableObject();
          public Builder setParameter1(String value) {
               instance.requiredParam1 = value;
               return this;
          }
          //etc for each parameter.

          public SomeImmutableObject build() {
             if (instance.requiredParam1 == null || instance.requiredParam2 == null /*etc*/)
                throw new IllegalStateException("All required parameters were not supplied.");
             return instance;
          }
      } 
 }

Обратите внимание, что вы можете выполнить в основном то же самое, сделав пакет полей частным и поместив построитель в тот же package.

И если по какой-то причине вы не можете этого сделать, вы все равно можете иметь конструктор с 10 параметрами, а затем сделать так, чтобы Builder был единственным, что вызывает этот конструктор, чтобы упростить использование API использовать.

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

Изменить: OP добавил комментарий (довольно давно, но я только что получил голосование по этому вопросу, поэтому я видел его только сейчас) с интересный вопрос: как вы проверяете примитив в более поздний момент времени?

Есть несколько способов обойти эту проблему, включая логическое значение защиты, но я предпочитаю использовать объект Double следующим образом:

     private Double doubleForPrimitive;

     public Builder setDouble(double d) {
         doubleForPrimitive = d;
     }

     public SomeImmutableObject build() {
         if(doubleForPrimitive != null) {
               instance.doubleParam = doubleForPrimitive;
         } else {
                throw new IllegalArgumentExcepion("The parameter double was not provided");
         }
         //etc.
     }

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

16
ответ дан 28 November 2019 в 06:02
поделиться

Эти два шаблоны полезны при рассмотрении такого сценария:

4
ответ дан 28 November 2019 в 06:02
поделиться

Если все параметры действительно необходимы, и вы не используете Spring для создания экземпляра bean-компонента, я бы определенно выбрал конструктор с 10 параметрами. Совершенно очевидно, что все параметры, по сути, требуются.

Если вы используете Spring (возможно, время от времени) для создания bean-компонента, или вам не очень нравится иметь много временных переменных в методе, который конструирует этот bean-компонент, вы также можете использовать методы получения и установки. Если вы также реализуете метод проверки для проверки правильности объекта, у вас не должно возникнуть проблем.

Однако метод проверки работает лучше всего, если вы используете его последовательно; возможно, имея Validatable интерфейс. Он очень хорошо вписывается в рабочий процесс, если это часть стиля программирования. Если есть только один или два класса, в которых используется эта парадигма, вероятно, этого не стоит.Вы все равно когда-нибудь забудете вызвать validate ().

Если вы не используете подход валидатора и не любите конструктор (хотя я не знаю, почему, он для этого), вы всегда можете вернуться к Строителям, упомянутым другими.

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

0
ответ дан 28 November 2019 в 06:02
поделиться
​​

ИМО, конструкторы не образуют хороший API при создании объектов, особенно когда количество аргументов велико и они одного типа.

new Person(String, String, String, String); // what the?? this is what may 
                                            // show up in IDEs

где на самом деле это означает «Человек» (имя, фамилия, экранное имя, пароль, (например, ради)

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

Другой подход, который вы могли бы принять, - рассмотреть возможность использования внутреннего DSL. Но это имеет смысл только в том случае, если вы создаете такие объекты, как конфигурации, запросы и т. д. Посмотрите, имеет ли смысл наличие внутреннего DSL в вашем case.

У нас была аналогичная проблема в нашем проекте. Нам нужно было получить определенные значения с домашнего шлюза (наш продукт). Он поддерживал протокол XML на основе запросов-ответов по http. Но создание объекта Request для отправки в пользовательском интерфейсе было утомительно, с настройкой объектов запроса остроумие h соответствующие параметры и фильтры и т. д.

Первоначально наш объект запроса выглядел так:

Request r = new Request("SET");
r.setAction("add"); // modify, add, delete
r.setModuleName("NPWIFI"):
r.addParameter(new Param("wifiAclMac", "aa:bb:cc:dd:ee:ff"));
r.addParameter(new Param("wifiCommit", "commit"));
r.setActionParam("wifiAclRowStatus")
r.addFilter(new Filter(Type.EQUALS, "wifiInterface", "wl0"));
r.addFilter(new Filter(Type.EQUALS, "wifiAclMac", "yourgateway"));

Resonse r = gwSession.sendRequest(r);

Итак, мы изменили его на внутренний DSL, который имел ощущение SQL, но только программно

Query q = DQL.add("wifiAclMac", "wifiCommit").into("NPWIFI").values
            ("aa:bb:cc:dd:ee:ff", "commit").withAp("wifiAclRowStatus")
            .where("wifiInterface").is("wl0")
            .and("wifiAclMac").is("aa:bb:cc:dd:ee:ff").end();

Объект DQL «построитель запросов» выполнял все построение с проверкой и также доказал быть очень удобным в использовании.

Построители и DSL - это элегантные и мощные средства создания и построения объектов, но посмотрите, что имеет смысл в вашем случае.

1
ответ дан 28 November 2019 в 06:02
поделиться

Без сомнения, это вопрос дизайна. Надо с легкостью взвесить удобочитаемость. Конструктор с десятью аргументами проще, но может быть или не быть более читаемым / обслуживаемым. У него также меньше вызовов методов для включения и выключения стека вызовов. Установка десяти различных значений с помощью сеттеров немного более понятна и понятна.Это не обязательно «проще» (хотя вы можете утверждать оба варианта) и добавляет больше вызовов методов для включения и выключения стека вызовов.

Но есть еще несколько моментов, о которых стоит подумать. Даже с конструктором с десятью аргументами вы можете попросить программиста передать значение null, пробел, false или ноль (в зависимости от объекта или примитива), что может быть или не совпадать с тем, что вы намеревались. Единственный способ контролировать это - потенциально вызвать исключение в конструкторе. Вы действительно хотите этим заниматься? Вы ожидаете такого поведения?

Конечно, устанавливая каждую переменную отдельно с помощью сеттеров, вы не сможете узнать, закончили ли вы создание объекта или нет. Здесь может помочь рассмотренный выше паттерн Строитель. Попросите его создать объект, установить значения, а затем убедиться, что все они установлены. Если чего-то не хватает из-за того, что программист решил что-то не передавать, значит, вы защищены. Вашему классу не нужно делать больше, чем положено. (В конце концов, важно подумать о том, кто может когда-нибудь использовать ваш класс. Они могут не понять вашего намерения, несмотря на всю великую Javadoc в мире.)

Наконец, я бы спросил, есть ли что-нибудь, что вам нужен дефолт? Потому что, если некоторые вещи могут использоваться по умолчанию, вы можете либо установить для них значения по умолчанию на уровне класса, либо установить их по умолчанию в конструкторе (в зависимости от ваших идеалов программирования, которые, по вашему мнению, являются более конкретными и помогают с поведением вашего объекта) .Тогда вы потенциально можете «предварительно установить» определенные поля, и вам нужно будет только переопределить их через сеттеры вручную или через сеттеры через Builder.

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

1
ответ дан 28 November 2019 в 06:02
поделиться

Я бы реализовал паттерн builder вот так:

package so1632058;

public class MyClass {
  private final String param1;
  private final String param2;

  MyClass(Builder builder) {
    this.param1 = builder.param1;
    this.param2 = builder.param2;
  }

  public String getParam1() {
    return param1;
  }

  public String getParam2() {
    return param2;
  }

  @SuppressWarnings("hiding")
  public static final class Builder {
    String param1;
    String param2;

    public Builder param1(String param1) {
      this.param1 = param1;
      return this;
    }

    public Builder param2(String param2) {
      this.param2 = param2;
      return this;
    }

    public MyClass toMyClass() {
      return new MyClass(this);
    }
  }
}

И затем имел бы следующий код для его использования:

package so1632058;

public class Main {

  public static void main(String[] args) {
    MyClass.Builder builder = new MyClass.Builder();
    builder.param1("p1").param2("p2");
    MyClass instance = builder.toMyClass();
    instance.toString();
  }

}

Некоторые замечания:

  • Нет методов с большим количеством параметров.
  • Дополнительная проверка может быть выполнена в конструкторе MyClass.
  • Я сделал видимость конструктора общепакетной, чтобы избежать предупреждения "synthetic-access".
  • То же самое для полей экземпляра конструктора.
  • Единственный способ создать экземпляр MyClass - это Builder.
2
ответ дан 28 November 2019 в 06:02
поделиться

Десять аргументов для конструктора - это много. Я бы серьезно подумал, все ли они требуются, и некоторые из них не имеет смысла объединять в логические объекты. Если действительно есть десять отдельных требуемых частей данных, то конструктор должен содержать десять полей.

3
ответ дан 28 November 2019 в 06:02
поделиться

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

  • Можно ли объединить некоторые из них в объекты «ценности» более высокого уровня? Например, переменные X и Y могут быть объединены в Point. У нас было много подобных ситуаций в программе маршрутизации грузов, где все поля были смоделированы как примитивные строки. Введение нескольких концепций более высокого уровня действительно помогло сделать его читабельным.
  • Можно ли установить для некоторых параметров определенные значения по умолчанию?
  • Действительно ли все они независимые, ортогональные концепции? Я работал над множеством систем и никогда не видел, чтобы это было правдой. Если нет, то есть над чем подумать.
1
ответ дан 28 November 2019 в 06:02
поделиться

В своей книге Code Complete Стив МакКоннелл утверждает, что ни одна процедура не должна иметь более 6, может быть, 7 аргументов. Большинство этих утверждений - не просто его мнение, а подкреплено исследованиями, например, частоты ошибок, связанных со структурой кода.

Чистый код Роберта Мартина идет еще дальше: Он рекомендует 1 или 2 аргумента, в то время как 3 уже считается "запахом кода". Лично я считаю, что Clean Code местами немного экстремален, но в целом он приводит несколько хороших аргументов.

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

Все это дает веские основания задуматься о сокращении количества параметров. В других ответах были предложены некоторые практические предложения.

20
ответ дан 28 November 2019 в 06:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: