Я занимаюсь рефакторингом платежного модуля для своего сайта. У него много провайдеров, режимов и операций, и они продолжают добавлять. Нужен совет по своей архитектуре - PullRequest
0 голосов
/ 19 апреля 2019

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

Я выполняю рефакторинг, используя команды для каждой операции для каждого провайдера. Скажем, команда для «проверки подлинности кредитной карты каким-либо провайдером A» и команда для «чистых банковских продаж провайдера B» и так далее.

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

PaymentCommand command = commandsManager.getFactory(emiScheme.getPaymentProvider().getCode())
                .create(PaymentActionEnum.EMI_SCHEME_VALIDATION.name());

        return (EmiSchemeValidationResult) command.execute(schemeValidationRequest);

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

1 Ответ

0 голосов
/ 19 апреля 2019

Ваши решения кажутся мне хорошими. Я использую подобные методы, и они хорошо работают.

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

Если вы имеете в виду такие принципы, как CQS , в которых говорится, что Команды не должны возвращать результаты, возможно, нам придется немного подробнее поговорить об определении Command . Этот принцип предназначен для объектов в ОО-системе и применяется к методам на объектах, а не для Команды как объекта, выполняющего некоторую логику приложения, как объясняет Мартин Фаулер здесь . Вы можете применять его везде, где вы как из couse. Никто не останавливает вас, но для того, чтобы полностью понять то, что вам нужно, теперь это задумано.

Лучше думать об этих методах команды как о мутаторах состояния объекта. Если они работают как мутаторы и запрашивают что-то, это может быть сложнее для понимания и использования. Однако иногда полезно иметь метод command / mutator , который изменяет состояние и возвращает результат. как в случае Stack.Pop () . Лучше придерживаться этого шаблона большую часть времени, но если вы не можете просто не делать этого.

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

Вот несколько способов сделать это:

  • Тот, который вы используете: Используйте разные типы для каждого результата и приведите к нему.

  • Не определяйте общий интерфейс для всех команд, таких как ICommand . Определите общий интерфейс для семейства команд. Сделайте так, чтобы ваша фабрика возвращала наиболее распространенный объект, подобный классу, который вы приведете позже к IPaymentCommand . Это будет интерфейс для всех PaymentCommands . IPaymentCommand.Execute вернет EmiSchemeValidationResult и ваш штраф. Я использовал это и хорошо работает, если вы заранее знаете тип, который вы собираетесь получить. Если ваш исполняемый код должен быть более общим, это может вызвать проблемы

  • Определите класс результата, который содержит пару ключ / значение с результатами (сохраните их в HashMap в Java, в Dictionary в C # что-то в этом роде). Вы имитируете пример JavaScript с этим. Хороший шаблон, но он сделает код обработки результатов команды более трудоемким для написания. Иногда это может даже стать неприятным и разозлить вас каждый раз, когда вам нужно написать это.

  • Добавить свойство с результатом к Command . Если у вас уже есть тип команды, такой как PaymentCommand . Добавьте к нему свойство EmiSchemeValidationResult PaymentCommand.Result и проверьте его после выполнения команды. Я тоже использовал этот шаблон, и он хорошо работал.

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

Вот статья, которая объясняет эти вещи более подробно: https://martinfowler.com/bliki/CommandOrientedInterface.html

...