作为软件工程师,我个人的目标是构建可运行,解决问题并且可维护,可扩展和高性能的软件。为此,以有组织的方式编写代码非常重要。因此很清楚每一段代码在做什么,避免重复并提高可维护性。
几周前,我们有一个需要摄取同一对象的要求,但是根据其中一个字段,对其进行完全不同的处理。最简单,最快的方法可能是使用不同的逻辑创建不同的类,并简单地使用多个“ if / else”语句来执行所需的过程。但是,如果我们没有两个流程,但是将来可能只有五个或十个流程,该怎么办?
在快节奏的行业中,我们往往会忘记许多这些问题已经建立了解决方案。因此,仅通过对Google进行快速研究,我就发现了策略模式。我以前曾经实现过这种模式,但是起初我没有想到它。但是,看到这就像隧道尽头的光芒!
策略模式 是使得能够在运行时选择的算法的行为的设计模式。在本教程中,我将解释一种使用spring框架并利用其依赖注入能力实现它的方法。
在本教程中,我创建了一个Spring Webflux项目,并为您提供了一些背景信息,该服务通过REST API从电子商务站点获取订单。这些订单可以用于个人或公司客户。
逻辑很简单,如果是来自单个客户的订单,我们希望使用有效的付款方式。我们将动态决定要处理传入订单的类。在下面的代码中,我省略了一些方法和构造函数,但是,我强烈建议您在 此处 获取完整的项目并自己进行测试。
步骤1:让我们创建订单模型,该模型将用于向我们的API提交订单。
<b>public</b> <b>class</b> Order { <b>public</b> enum MethodOfPayment { CREDIT_CARD, DEBIT_CARD, CORPORATE_ACCOUNT } <b>public</b> enum OrderType{ CORPORATE, INDIVIDUAL } <b>private</b> Customer customer; <b>private</b> OrderType orderType; <b>private</b> String corpCode; <b>private</b> MethodOfPayment methodOfPayment; <b>private</b> Corporation corporation; <b>private</b> List<String> articles; <font><i>//methods omitted for this post. Visit the github project for more.</i></font><font> } </font>
步骤2:为您的处理类创建一个 接口 :
<b>public</b> <b>interface</b> OrderProcessingService { <font><i>//In here we define that all implementations must take an order</i></font><font> </font><font><i>// and return an OrderApiResponse.</i></font><font> Mono<OrderApiResponse> processOrder(Order order); } </font>
我们已经创建了此接口来定义一种所有处理订单的合同。
步骤3:为每个处理流创建 实现 ,并使用@Component Annotation对其进行注释。
@Component(<font>"CORPORATE"</font><font>) <b>public</b> <b>class</b> CorporateOrderProcessingService implements OrderProcessingService { @Override <b>public</b> Mono<OrderApiResponse> processOrder(Order order) { <b>return</b> Mono.just(order) .handle(<b>this</b>.handleOrder()); } } </font><font><i>// Constructor and other methods omitted for this post but available in the full project.</i></font><font> </font>
@Component(<font>"INDIVIDUAL"</font><font>) <b>public</b> <b>class</b> IndividualOrderProcessingService implements OrderProcessingService { @Override <b>public</b> Mono<OrderApiResponse> processOrder(Order order){ <b>return</b> Mono.just(order) .handle(<b>this</b>.handleOrder()); } } </font><font><i>// Constructor and other methods omitted for this post but available in the full project.</i></font><font> </font>
注意我们如何给每个注释一个特定的名称,该名称与我们的订单模型中定义的OrderType枚举相关。这将帮助我们确定对特定消息使用哪种实现。
第4步:在 Controller 类中将所有内容粘合在一起:
@RestController <b>public</b> <b>class</b> OrderController { <b>private</b> <b>final</b> Map<String, OrderProcessingService> orderProcessingServices; <font><i>//Spring will autowire our map with both immplementations and the Component name as the key</i></font><font> <b>public</b> OrderController(Map<String, OrderProcessingService> orderProcessingServices) { <b>this</b>.orderProcessingServices = orderProcessingServices; } @PostMapping(</font><font>"/order"</font><font>) <b>public</b> Mono<OrderApiResponse> onNewOrder(@RequestBody Order receivedOrder) { <b>return</b> <b>this</b>.orderProcessingServices.get(receivedOrder.getOrderType().name()) .processOrder(receivedOrder); } } </font>
在此控制器类中,我们使用了带字符串键的Map和OrderProcessingService的实例。Spring的魔力将注入该类型的所有可用bean,并通过其构造函数将组件名称用作此映射中的键。端点/order接受到Order对象以后,我们将基于orderType字段动态选择要使用的策略实现。