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



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



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");
......
}


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

731   15  

15 ответов:

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

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

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

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

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

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

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

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

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

С помощью статического импорта Вы можете создать внутренние fluent API:

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

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

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

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

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

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

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

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

Это также значительно повышает читаемость.

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();

вы также можете поместить логику проверки в установленной застройщиком..() и построить() методы.

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

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

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

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

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

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

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

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

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

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

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

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

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

посмотреть Принцип Единой Ответственности

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

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

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

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

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

Comments

    Ничего не найдено.