Должен ли список параметров метода содержать объекты или идентификаторы объектов?

10

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

Допустим, у нас есть два следующих метода:

public Response Withdraw(int clubId, int terminalId,int cardId, string invoice, decimal amount);

public Response Withdraw(Club club, Terminal terminal,Card card, string invoice, decimal amount);

то, что отправлено по проводам, это просто идентификаторы.

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

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

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

Какой правильный подход?

Может быть, есть третий, еще лучший подход?

Mithir
источник
Что? ...........
Джеймс
1
Контекст? Веб-сервис? WCF?
CodesInChaos
1
@James - извините, я написал этот вопрос довольно быстро, вы можете сказать мне, что не понято, чтобы я мог отредактировать его?
Mithir
@CodesInChaos методы на самом деле являются методами BL
Mithir

Ответы:

10

Ответ зависит от контекста.

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

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

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

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

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

c_maker
источник
3
+1 Я бы добавил еще один момент: для методов, вызываемых удаленно («по проводам»?), Передача объектов может повлечь за собой глубокую сериализацию обширного дерева объектов. Идентификаторы являются отличной заменой для объектов, когда вас беспокоит размер полезных данных удаленного вызова.
Росс Паттерсон
1
В этом случае похоже, что вы связаны с набором абстракций, поэтому передача идентификаторов не принесет вам большей гибкости и, вероятно, увеличит вероятность изменения параметров. Вопрос в том, насколько тесно код в методе связан с абстракциями, которые я передаю? Например, такой метод, как «validateCreditCard (string card, string cvi)», вероятно, должен оставаться с примитивами, чтобы избежать тесной связи с каким-либо объектом CreditCard.
ipaul
Я бы встретился посередине и использовал бы интерфейс в списке параметров. Тогда ваш клуб может быть клубом, а в будущем также сауной.
Питер Б
13

Первый подход свидетельствует о примитивной одержимости . Поскольку вы передаете ints и строки, программисту очень легко ошибиться (например, передавая clubId в параметр TerminalId). Это приведет к трудностям поиска ошибок.

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

Несмотря на это, я все равно посмотрю string invoice. Счет действительно является строкой? Что amountзначит? Это, скорее, денежная стоимость.

Вы упомянули в своем вопросе «то, что отправлено по проводам, это просто идентификаторы». Это правильно, но не позволяйте этому требованию запутать ваш домен.

Лучшее объяснение, которое я видел в пользу этого подхода, было в правиле 3 Object Calisthenics :

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

MattDavey
источник
Итак, второй подход предпочтительнее? даже если есть объект club с заполненным только свойством id?
Mithir
Это похоже на случайный блог. Там нет доказательств, чтобы сказать, что предпочтительнее. Кого волнует, что предпочтительнее? Делай то, что работает для тебя
Джеймс
@ Джеймс Нет однозначного ответа на этот вопрос, тем более что ОП не дал нам очень много контекста. Любой, кто категорически утверждает, что один подход предпочтительнее другого, оказывает ФП медвежью услугу. Это не то, что черно-белое.
MattDavey
1
@James Я просто указал, что первый подход позволяет очень легко вводить трудно найти ошибки. Я не говорю, что примитивные типы - это плохо, но цель примитивных типов - создать значимые типы доменов. Использование их вне этого контекста - само определение запаха примитивного кода одержимости.
MattDavey
5
@James: То, что сказал МэттДейви, является общепризнанным фактом. Он не говорит, что нативные типы плохие, он говорит, что это: someMethod (int, int, int, string, decimal) намного сложнее для понимания и использования клиентом, чем someMethod (Club, Terminal, Card, String). , десятичное число)
c_maker
2

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

Если вы отправляете идентификатор, то обе системы должны быть тесно связаны с тем, что это представляет. ClubID является ключевым в таблице клубов. Более того, и вызывающему, и вызываемому абоненту необходимо согласовать, как называется таблица «Клубы» и в какой базе данных она находится. Если вы не хотите или не можете наложить это ограничение, тогда вы передадите объект, используя некоторое общее описание, родной, сериализованный, xml, name = value, ini-файл :)

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

Тони Хопкинсон
источник