2010-01-28 2 views
3

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

SomeClass[string] someFunction(SomeClass!(TemplateParam) foo, 
    string[][string] someAA, uint[] dataToProcess, SomeEnumType flag) { 
    // Do stuff. 
} 

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

ответ

7

Для такого рода ситуации, я, как правило, форматировать его, как это:

SomeClass[string] someFunction(
    SomeClass!(TemplateParam) foo, 
    string[][string] someAA, 
    uint[] dataToProcess, 
    SomeEnumType flag 
) 
{ 
    // Do stuff. 
} 
+0

Согласен. Для * очень * длинных списков параметров один параметр для каждой строки также имеет свои собственные проблемы ... но я никогда не видел другого решения, которое работает лучше, если вам нужен длинный список параметров. Я также склонен сопоставлять типы и имена параметров, когда я это делаю ... может сделать его немного читабельнее. – SuperMagic

+0

Кроме того, если ваш список параметров намного длиннее этого, это хороший признак того, что некоторые рефакторинг в порядке. – Aaron

1

I перегруппировать параметры в (главным образом внутреннем) классе (или структуру), чтобы избежать большого объявления функции/называем

+0

Я тоже слышал о том, что люди тоже это делают, но мне не очень нравится идея создания нового класса или структуры только для обработки параметров функции. Я мог бы быть в порядке с этой идеей, если тот же список параметров (следовательно, тот же самый параметр class/struct) используется несколько раз. Я не говорю, что это плохая идея, просто мне лично это не нравится. – Aaron

+0

Когда я использую стороннюю библиотеку, и я натыкаюсь на метод со многими параметрами (я помню один с 17!) С дюжиной булевых флагов, я хочу, чтобы создатель этого метода frankenstein использовал класс для их перегруппировки в одном или больше занятий! – Guillaume

0

Мне нравится ответ Аарона, просто давая новую строку для каждого параметра.

Когда это становится слишком большим, то пришло время немного реорганизовать.

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

2
  • для удобочитаемости - ставить каждый аргумент на новой линии
  • ради практичности и лучше API Desgin - аргументы, связанные группы в новые классы, тем самым сокращая количество аргументов.
1

Вы можете ввести объект параметра:

class ParameterObject { 
    public final SomeClass!(TemplateParam) foo; 
    public final string[][string] someAA; 
    public final uint[] dataToProcess; 
    public final SomeEnumType flag; 

    private ParameterObject(
     SomeClass!(TemplateParam) foo, 
     string[][string] someAA, 
     uint[] dataToProcess, 
     SomeEnumType flag) { 
     this.foo = foo; 
     this.someAA = someAA; 
     this.dataToProcess = dataToProcess; 
     this.flag = flag; 
    } 

    private static class Builder { 
     public SomeClass!(TemplateParam) foo; 
     public string[][string] someAA; 
     public uint[] dataToProcess; 
     public SomeEnumType flag; 

     public Builder foo(SomeClass!(TemplateParam) foo) { 
      this.foo = foo; 
      return this; 
     } 

     public Builder someAA(string[][string] someAA) { 
      this.someAA = someAA; 
      return this; 
     } 

     public Builder dataToProcess(uint[] dataToProcess) { 
      this.dataToProcess = dataToProcess; 
      return this; 
     } 

     public Builder flag(SomeEnumType flag) { 
      this.flag = flag; 
      return this; 
     } 

     public ParameterObject build() { 
      if (null == foo) throw Exception("init foo!"); 
      if (null == someAA) throw Exception("init someAA!"); 
      if (null == dataToProcess) throw Exception("init dataToProcess!"); 
      if (null == flag) throw Exception("init flag!"); 
      return new ParameterObject(foo, someAA, dataToProcess, flag); 
     } 
    } 
} 

Теперь, ваш звонок будет выглядеть, например:

SomeClass[string] myValue = 
    someFunction(
     new ParameterObject.Build(). 
      foo(myFoo). 
      someAA(myAA). 
      dataToProcess(myData). 
      flag(false). 
      build() 
    ); 

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

someFunction(
    Map.new(
     foo => myFoo, 
     someAA => myAA, 
     dataToProcess => myData, 
     flag => false 
    ) 

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

+0

Это абсурдно многословный. – dsimcha

+0

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

+1

Пожалуйста, не оставляйте точку в конце исходного выражения, это странно. Строка, начинающаяся с точки, является четкой индикацией того, что она является продолжением вызова из предыдущей строки. –