使用Spring实施策略模式 - javarevisited


作为软件工程师,我个人的目标是构建可运行,解决问题并且可维护,可扩展和高性能的软件。为此,以有组织的方式编写代码非常重要。因此很清楚每一段代码在做什么,避免重复并提高可维护性。
几周前,我们有一个需要摄取同一对象的要求,但是根据其中一个字段,对其进行完全不同的处理。最简单,最快的方法可能是使用不同的逻辑创建不同的类,并简单地使用多个“ if / else”语句来执行所需的过程。但是,如果我们没有两个流程,但是将来可能只有五个或十个流程,该怎么办?
在快节奏的行业中,我们往往会忘记许多这些问题已经建立了解决方案。因此,仅通过对Google进行快速研究,我就发现了策略模式。我以前曾经实现过这种模式,但是起初我没有想到它。但是,看到这就像隧道尽头的光芒!
策略模式是使得能够在运行时选择的算法的行为的设计模式。在本教程中,我将解释一种使用spring框架并利用其依赖注入能力实现它的方法。
在本教程中,我创建了一个Spring Webflux项目,并为您提供了一些背景信息,该服务通过REST API从电子商务站点获取订单。这些订单可以用于个人或公司客户。
逻辑很简单,如果是来自单个客户的订单,我们希望使用有效的付款方式。我们将动态决定要处理传入订单的类。在下面的代码中,我省略了一些方法和构造函数,但是,我强烈建议您在此处获取完整的项目并自己进行测试。

步骤1:让我们创建订单模型,该模型将用于向我们的API提交订单。

public class Order {

  public enum MethodOfPayment {

    CREDIT_CARD,
    DEBIT_CARD,
    CORPORATE_ACCOUNT

  }

  public enum OrderType{
    CORPORATE,
    INDIVIDUAL
  }

  private Customer customer;
  private OrderType orderType;
  private String corpCode;
  private MethodOfPayment methodOfPayment;
  private Corporation corporation;
  private List<String> articles;

  //methods omitted for this post. Visit the github project for more.
}

步骤2:为您的处理类创建一个接口

public interface OrderProcessingService {
 //In here we define that all implementations must take an order
  // and return an OrderApiResponse.
  Mono<OrderApiResponse> processOrder(Order order);

}

我们已经创建了此接口来定义一种所有处理订单的合同。

步骤3:为每个处理流创建实现,并使用@Component Annotation对其进行注释。

@Component("CORPORATE")
public class CorporateOrderProcessingService implements OrderProcessingService {


  @Override
  public Mono<OrderApiResponse> processOrder(Order order) {
    return Mono.just(order)
        .handle(this.handleOrder());
  }

}
  // Constructor and other methods omitted for this post but available in the full project.


@Component("INDIVIDUAL")
public class IndividualOrderProcessingService implements OrderProcessingService {

  @Override
  public Mono<OrderApiResponse> processOrder(Order order){
    return Mono.just(order)
          .handle(this.handleOrder());
  }
  
}
  // Constructor and other methods omitted for this post but available in the full project.

注意我们如何给每个注释一个特定的名称,该名称与我们的订单模型中定义的OrderType枚举相关。这将帮助我们确定对特定消息使用哪种实现。

第4步:在Controller类中将所有内容粘合在一起:

@RestController
public class OrderController {

  private final Map<String, OrderProcessingService> orderProcessingServices;
  
  //Spring will autowire our map with both immplementations and the Component name as the key
  public OrderController(Map<String, OrderProcessingService> orderProcessingServices) {
    this.orderProcessingServices = orderProcessingServices;
  }

  @PostMapping("/order")
  public Mono<OrderApiResponse> onNewOrder(@RequestBody Order receivedOrder) {
   
    return this.orderProcessingServices.get(receivedOrder.getOrderType().name())
        .processOrder(receivedOrder);

  }

}


在此控制器类中,我们使用了带字符串键的Map和OrderProcessingService的实例。Spring的魔力将注入该类型的所有可用bean,并通过其构造函数将组件名称用作此映射中的键。端点/order接受到Order对象以后,我们将基于orderType字段动态选择要使用的策略实现。