我正在为我的网站重构支付模块.它有许多提供商,模式和操作,并且它们不断添加.需要有关其架构的建议



当前编写的支付模块使用 if-else 块为不同的支付提供商、支付模式和操作执行操作。当需要添加另一个这些提供程序或模式或操作时,人们只是复制和粘贴另一个其他 - 如果。

我正在通过为每个提供程序的每个操作使用命令来重构它。比如说,一个用于"某个提供商 A 的信用卡身份验证"的命令和一个用于"提供商 B 的网上银行销售"的命令等等。

问题是命令不返回值,但我已经让他们这样做了。现在没有对返回类型进行严格的类型检查。在服务中,我正在调用命令,我必须进行显式类型转换,如下所示:

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

在这里使用命令是合法的副作用吗?还是我应该以其他方式使用命令来返回结果?还是我应该使用其他东西来解决我的问题?

你的解决方案对我来说似乎很好。我使用类似的技术,它们效果很好。

命令封装一些应用程序逻辑是一个很好的模式,从中返回结果并不是一件坏事。如果不这样做,这意味着您将不得不进行其他查询才能找出结果,这可能会导致性能不佳。为什么从命令返回结果以避免对数据库进行一次或多次调用是不好的?

如果您指的是像 CQS 这样说命令不应返回结果的原则,我们可能不得不更多地讨论命令的定义。这个原则适用于对象系统中的对象,适用于对象上的方法,而不是像MartinFowler在这里解释的那样,命令作为执行一些应用程序逻辑的对象,你可以把它应用到任何你喜欢的地方。没有人阻止你,但为了完全理解你需要的东西,现在它被构思了。

最好将这些命令方法视为对象的状态突变器。如果它们同时作为突变器和查询服务器,则可能更难理解和使用。但是,有时使用命令/突变器方法来更改状态并返回结果很有用。就像Stack.Pop()的情况一样。最好在大多数时候坚持这种模式,但如果你不能,就不要。

定义一个公共接口,该接口应返回在强类型语言中可能不同的结果可能具有挑战性。如果你用像JavaScript这样的语言来做,那么这不是问题。您要么返回结果,要么不返回结果。如果这样做,则接收器将检查此对象具有哪些属性。根据我对松散类型和强类型语言的经验,这是更容易实现的事情之一。因为您有从同一方法返回的动态数据。

这里有几种不同的方法可以做到这一点:

  • 您使用的那个:对每个结果使用不同的类型并强制转换为该结果。

  • 不要为所有命令(如ICommand)定义通用接口。为一系列命令定义通用接口。使工厂返回最常见的类(如对象),稍后将强制转换为IPaymentCommand。这将是所有付款命令的接口。IPaymentCommand.Execute将返回EmiSchemeValidationResult和您的罚款。我已经使用了它,如果您事先知道将要收到的类型,我会很好地工作。如果执行代码需要更通用,这可能会导致问题

  • 定义一个包含结果的键/值对的结果类(将它们存储在 Java 的 HashMap 中,存储在 C# 中的字典中)。你用这个模拟JavaScript的例子。良好的模式,但它会使命令结果处理代码代码编写起来更麻烦。有时它甚至会变得令人讨厌,每次你需要写它时都会惹恼你。

  • 将包含结果的属性添加到命令中。如果您已经拥有命令的类型,例如付款命令。将EmiSchemeValidationResult PaymentCommand.Result属性添加到其中,并在命令执行后进行检查。我也使用过这种模式,效果很好。

这取决于你的代码的需求以及你(和/或你的团队)对什么感到满意。

这里有一篇文章更详细地解释了这些事情: https://martinfowler.com/bliki/CommandOrientedInterface.html

最新更新