Работа с множеством входных параметров, много выходов - PullRequest
3 голосов
/ 09 декабря 2008

Мне нужно выполнить сложный расчет. В моем случае было наиболее естественно создать класс Calculator (абстрагированный с использованием шаблона стратегии).

Для выполнения вычислений класс должен принять около 20 входных данных, некоторые из которых являются необязательными, некоторые из них могут измениться в будущем и т. Д. После вызова метода Calculate () примерно 20 различных переменные должны быть выведены.

Существует несколько способов достижения этого.

  • Входные данные, переданные в качестве параметров в метод расчета
  • Входные данные, переданные через свойства Калькулятора
  • Входные данные упакованы в собственный класс, а затем переданы в метод Calculate ().
  • Выходы, возвращаемые функцией Calculate (), заключенные в класс
  • Выходы, заполненные параметром, переданным методу Calculate ()
  • Выводы, извлеченные из открытых свойств Калькулятора, после того, как Calculate () был вызван

Есть плюсы и минусы всех этих методов. Как бы вы это сделали?

UPDATE: Спасибо за отзыв.

Целью этого калькулятора является генерация цитаты. Входными данными являются такие вещи, как адрес клиента, процентные ставки, целевая прибыль, дополнительные сборы, идентификатор продукта и т. Д. Выходные данные включают в себя цитату, фактическую прибыль, дополнительные сборы и т. Д.

Я разработал интерфейсы ICalculateInput и ICalculateOutput и их конкретные классы, и теперь система работает очень хорошо. Класс Calculator также унаследован от интерфейса ICalculator (поскольку используемые вычисления сильно различаются в зависимости от компании, из которой поставляется продукт).

Ответы [ 10 ]

4 голосов
/ 09 декабря 2008

Я бы порекомендовал

  • Входные данные упакованы в их собственный класс, а затем переданы в метод Calculate ().
  • Выходы, возвращаемые Calculate (), упакованные в класс

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

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

Мутирование параметров для генерации вывода - плохая идея. со стороны вызывающих не очевидно, что класс, которым он «владеет», был изменен путем передачи его в функцию.

3 голосов
/ 09 декабря 2008

Большинство людей предлагают использовать «Класс параметров» и «Класс результатов». Я согласен с таким подходом, но мне кажется, что ваши параметры делятся на несколько категорий. Возможно, вы могли бы создать класс параметров для обязательных параметров и отдельный класс параметров для необязательных параметров или групп необязательных параметров. Таким образом, вы можете создавать разные методы в зависимости от того, какой тип расчета вам требуется;

Result calculate(RequiredArgs requiredArgs) {
...
}

Result calculate(RequiredArgs requiredArgs, OptionalArgs optionalArgs) {
}

Result calculate(RequiredArgs requiredArgs, OptionalArgs optionalArgs, OtherOptionalArgs oOpitonalArgs) {
}

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

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

1 голос
/ 10 декабря 2008

вы оставили

  • входные данные помещаются в словарь, который передается в Calculate

Удивительно, почему у вас есть 20 входов для одной функции ... кажется чрезмерным. Но если они вам нужны, а некоторые являются необязательными, и метод расчета может быть изменен в будущем с помощью шаблона «Стратегия», тогда имеет смысл передать коллекцию именованных переменных. Вы можете даже указать шаблон Стратегии в коллекции, чтобы метод Calculate был полностью универсальным

1 голос
/ 09 декабря 2008

Я согласен, что ваши входы и выходы должны содержаться в своих собственных классах.

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

1 голос
/ 09 декабря 2008

Как правило, не создавайте методы, которые принимают более 3-4 отдельных параметров

Что-то, что вы не должны делать в JavaScript:

var addUser = function (name,surname, age, add1, add2, telephone) {
    //do something
};

Вместо вышесказанного лучше сделать что-то вроде:

var addUser = function (userDetails) {
    //Do something with userDetails.name etc...
};
//Then invoke the function by passing in an object:
var ud = {name : 'Andreas', surname : 'Grech', age : 20, add1 : 'bla', add2 : 'bla', telephone : 12343}; 
addUser(ud);

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

1 голос
/ 09 декабря 2008

Длинные списки параметров становятся обременительными и подверженными ошибкам. Расскажите нам немного больше о приложении и среде, но в целом было бы заманчиво передать объект какого-либо класса или использовать список или тому подобное.

Один изящный способ справиться с этим, который я сделал, - это использовать шаблон Composite. В Java вы можете, например, создать интерфейс для параметра, а затем составить список объектов, реализующих параметр.

0 голосов
/ 10 декабря 2008

Предполагая, что вы уже много думали об этом и определили, что да, вам действительно нужны все эти параметры:

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

Для вывода я бы, скорее всего, вернул объект, если возвращается более одного значения.

0 голосов
/ 09 декабря 2008

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

0 голосов
/ 09 декабря 2008

Попробуйте сделать то, что делают классы провайдера базы данных в .net.

Иметь класс параметров (со свойством типа и значения с направлением, т. Е. Ввод / вывод) и иметь параметры (набор параметров) в качестве свойства Калькулятора.

Подробнее см. В классе OleDBCommand / SQLCommand в .net, который используется для вызова хранимых процедур / функций.

0 голосов
/ 09 декабря 2008

Вы не упомянули язык, но я предполагаю, что c #. Я бы, вероятно, передал их в виде структуры (или класса) и вернул бы выходные данные таким же образом.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...