Лучшая практика передачи многих аргументов методу?

Иногда мы должны писать методы, которые получают много аргументов, например:

public void doSomething(Object objA , Object objectB ,Date date1 ,Date date2 ,String str1 ,String str2 )
{
}

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

Map<Object,Object> params = new HashMap<Object,Object>();
params.put("objA",ObjA) ;

......

public void doSomething(Map<Object,Object> params)
{
 // extracting params 
 Object objA = (Object)params.get("objA");
 ......
 }

Это не очень хорошая практика, инкапсуляция параметров на карту - это полная трата эффективности. Хорошо, чистая подпись, легко добавить другие параметры с наименьшей модификацией. какова наилучшая практика для такого рода проблем?

Ответ 1

В Эффективная Java, глава 7 (Способы), пункт 40 (Подготовительные письма метода проектирования), Блох пишет:

Существует три метода сокращения слишком длинных списков параметров:

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

Для более подробной информации я рекомендую вам купить книгу, она действительно того стоит.

Ответ 2

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

Вместо этого используйте модель. Создайте класс, который будет контейнером для всех этих параметров. Таким образом, вы сохраняете безопасность Java. Вы также можете передать этот объект другим методам, поместить его в коллекции и т.д.

Конечно, если набор параметров не используется в другом месте или не проходит, выделенная модель может быть переполнена. Там должен быть баланс, поэтому используйте здравый смысл.

Ответ 3

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

exportWithParams().datesBetween(date1,date2)
                  .format("xml")
                  .columns("id","name","phone")
                  .table("angry_robots")
                  .invoke();

Используя статический импорт, вы можете создавать внутренние бедные API:

... .datesBetween(from(date1).to(date2)) ...

Ответ 4

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

XXXParameter param = new XXXParameter(objA, objB, date1, date2, str1, str2);
// ...
doSomething(param);

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

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

Ответ 5

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

Ответ 6

Существует шаблон, называемый объект параметра.

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

Ответ 7

Это часто является проблемой при создании объектов.

В этом случае используйте шаблон объекта-конструктора, он хорошо работает, если у вас есть большой список параметров и не всегда нужно их всех.

Вы также можете адаптировать его к вызову метода.

Это также повышает удобочитаемость.

public class BigObject
{
  // public getters
  // private setters

  public static class Buider
  {
     private A f1;
     private B f2;
     private C f3;
     private D f4;
     private E f5;

     public Buider setField1(A f1) { this.f1 = f1; return this; }
     public Buider setField2(B f2) { this.f2 = f2; return this; }
     public Buider setField3(C f3) { this.f3 = f3; return this; }
     public Buider setField4(D f4) { this.f4 = f4; return this; }
     public Buider setField5(E f5) { this.f5 = f5; return this; }

    public BigObject build()
    {
      BigObject result = new BigObject();
      result.setField1(f1);
      result.setField2(f2);
      result.setField3(f3);
      result.setField4(f4);
      result.setField5(f5);
      return result;
    }
  }
}

// Usage:
BigObject boo = new BigObject.Builder()
  .setField1(/* whatever */)
  .setField2(/* whatever */)
  .setField3(/* whatever */)
  .setField4(/* whatever */)
  .setField5(/* whatever */)
  .build();

Вы также можете поместить логику проверки в методы Builder set..() и build().

Ответ 8

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

Ответ 9

Code Complete * предлагает несколько вещей:

  • "Ограничьте количество рутинных параметров примерно до семи. Семь - волшебное число для понимания людей" (стр. 108).
  • "Поместите параметры в порядок ввода-изменения-вывода... Если несколько подпрограмм используют аналогичные параметры, поместите аналогичные параметры в последовательном порядке" (стр. 105).
  • Поставьте текущие данные о состоянии или ошибках.
  • Как упоминалось tvanfosson, передайте только части структурированных переменных (объектов), которые необходимы подпрограмме. Тем не менее, если вы используете большую часть структурированной переменной в функции, просто передайте всю структуру, но помните, что это способствует некоторой связи.

* Первое издание, я знаю, что я должен обновить. Кроме того, вероятно, что некоторые из этих советов, возможно, изменились с тех пор, как второе издание было написано, когда ООП начал становиться более популярным.

Ответ 10

Хорошей практикой будет рефакторинг. Что относительно этих объектов означает, что они должны быть переданы этому методу? Должны ли они быть инкапсулированы в один объект?

Ответ 11

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

Более простым способом было бы группировать все параметры в объекте bean, но это все еще не полностью устраняет проблему.

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

Вам нужен лучший дизайн приложения, а не лучшая практика для отправки множества параметров.

Ответ 12

Создайте класс bean и задайте все параметры (метод setter) и передайте этот объект bean методу.

Ответ 13

Это часто свидетельствует о том, что ваш класс несет более одной ответственности (т.е. ваш класс слишком много).

См. Принцип единой ответственности

для более подробной информации.

Ответ 14

Если вы передаете слишком много параметров, попробуйте реорганизовать метод. Возможно, он делает много вещей, которые он не должен делать. Если это не так, попробуйте подставить параметры одним классом. Таким образом вы можете инкапсулировать все в один экземпляр класса и передать экземпляр вокруг, а не параметры.

Ответ 15

  • Посмотрите на свой код и посмотрите, почему все эти параметры передаются. Иногда можно реорганизовать сам метод.

  • Использование карты оставляет ваш метод уязвимым. Что делать, если кто-то, использующий ваш метод, пропускает имя параметра или отправляет строку, в которой ваш метод ожидает UDT?

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

Ответ 16

Это старый поток, но если у вас есть аналогичные аргументы, вы можете использовать varargs

Что-то вроде

public void doSomething (объекты Object..) { }