1、需求+分析

核算每个订单的不同成本项目,每个订单的成本项目通过设置公式算出,而公式里每个公式元素的计算方式都不一样,所以此处使用策略模式就非常合适。

2、实现

枚举:

  1. public enum CostCalElementType {
  2. PUR_DP_COST("外购门板费用", "1001"),
  3. PUR_MAT_COST("其他材料费", "1002"),
  4. ORDER_AMOUNT("订单总金额", "1003"),
  5. ORDER_ACTUAL_AMOUNT("应付总金额", "1004");
  6. private String name;
  7. private String no;
  8. CostCalElementType(String name, String no) {
  9. this.name = name;
  10. this.no = no;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public String getNo() {
  19. return no;
  20. }
  21. public void setNo(String no) {
  22. this.no = no;
  23. }
  24. }

注解:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface CostCalElementAnnotation {
  4. CostCalElementType type();
  5. }

抽象策略类:

  1. public interface CostCalElementStrategy {
  2. Map<String, Float> calculate(Set<String> orderNos);
  3. }

具体策略类:

  1. @Service
  2. @CostCalElementAnnotation(type = CostCalElementType.ORDER_ACTUAL_AMOUNT)
  3. public class ActualAmountStrategy implements CostCalElementStrategy {
  4. @Override
  5. public Map<String, Float> calculate(Set<String> orderNos) {
  6. System.out.println("应付总金额计算");
  7. return Collections.emptyMap();
  8. }
  9. }
  10. @Service
  11. @CostCalElementAnnotation(type = CostCalElementType.ORDER_AMOUNT)
  12. public class OrderAmountStrategy implements CostCalElementStrategy {
  13. @Override
  14. public Map<String, Float> calculate(Set<String> orderNos) {
  15. System.out.println("订单总金额计算");
  16. return Collections.emptyMap();
  17. }
  18. }
  19. @Service
  20. @CostCalElementAnnotation(type = CostCalElementType.PUR_DP_COST)
  21. public class PurDpCalStrategy implements CostCalElementStrategy {
  22. @Override
  23. public Map<String, Float> calculate(Set<String> orderNos) {
  24. System.out.println("外购门板费用计算");
  25. return Collections.emptyMap();
  26. }
  27. }
  28. @Service
  29. @CostCalElementAnnotation(type = CostCalElementType.PUR_MAT_COST)
  30. public class PurMatCalStrategy implements CostCalElementStrategy {
  31. @Override
  32. public Map<String, Float> calculate(Set<String> orderNos) {
  33. System.out.println("其他材料费用计算");
  34. return Collections.emptyMap();
  35. }
  36. }

工厂类:根据具体策略类上CostCalElementAnnotation注解中 type 属性的值与传入的 CostCalElementType枚举比对,从工厂类中得到需要的具体策略类。如果从工厂类中找不到对应的策略类则报错!报错导致的原因可能是忘记在具体策略类上加注解或者真的没有这个策略类。

  1. @Component
  2. public class CostCalElementFactory {
  3. private final List<CostCalElementStrategy> costCalElementStrategies;
  4. public CostCalElementFactory(List<CostCalElementStrategy> costCalElementStrategies) {
  5. this.costCalElementStrategies = costCalElementStrategies;
  6. }
  7. public CostCalElementStrategy getCostCalElementStrategy(CostCalElementType costCalElementType) {
  8. return costCalElementStrategies.stream()
  9. .filter(
  10. strategy -> {
  11. Class<? extends CostCalElementStrategy> clazz = strategy.getClass();
  12. if (clazz.isAnnotationPresent(CostCalElementAnnotation.class)) {
  13. CostCalElementAnnotation costCalElementAnnotation =
  14. clazz.getAnnotation(CostCalElementAnnotation.class);
  15. return costCalElementAnnotation.type().equals(costCalElementType);
  16. }
  17. return false;
  18. })
  19. .findFirst()
  20. .orElseThrow(
  21. () -> new RuntimeException(String.format("找不到%s对应的策略!", costCalElementType.getName())));
  22. }
  23. }

测试类:

  1. @SpringBootTest
  2. public class CostCalElementStrategyTest {
  3. @Autowired private CostCalElementFactory costCalElementFactory;
  4. @Test
  5. public void test() {
  6. Map<String, Float> calculate =
  7. costCalElementFactory
  8. .getCostCalElementStrategy(CostCalElementType.PUR_MAT_COST)
  9. .calculate(Collections.emptySet());
  10. }
  11. }