基于Spring自动注入的策略模式

本文介绍了一种利用策略模式和Spring框架解决多类型活动CRUD操作问题的方法。通过将不同活动类型的service注入到Map中,并利用枚举类型区分,实现了代码的整洁和灵活扩展。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 背景:

  • 比如我现在要一个具体的活动进行crud
  • 但我的活动分成多种活动模式如:秒杀,折扣等,这样就不能统一对具体活动进行crud

二 传统方式:

  • 1,我就要通过创建不同活动类型的service如:ISeckillActivityService,IDiscountActivityService等

  • 2,在要进行crud的地方,通过活动的类型去做if判断/switch,来调用相应的service,再进行crud操作

  • 缺点: 这样代码中会有大量的if或者switch

三 解决方式

  • 基于Spring自动注入的策略模式

1> 类结构关系图

在这里插入图片描述
如图:由于IDiscountActivityService 和ISeckillActivityService 都继承了BaseActivityService ,
spring提供了根据类型注入bean的特性,我们可以将同一种类型的bean注入到一个map中而具体的service(bean)的key为其id

2> 具体java类

策略模式关键类

  • BaseActivityService需要统一操作的接口方法
/**
 * @description: 活动基础service
 * @author: kismet
 * @create: 2018-10-25 11:48
 */
public interface BaseActivityService {

    /**
     * 添加活动
     * @return
     */
    Long addActivity(ActivityVo vo);
    /**
     * 更新活动
     * @return
     */
    void upDateActivity(ActivityVo vo);
}
  • IDiscountActivityService 折扣活动接口
/**
 * @description:折扣活动
 * @author: kismet
 * @create: 2018-10-25 11:50
 */
public interface IDiscountActivityService extends BaseActivityService {
}
  • ISeckillActivityService 秒杀活动接口
/**
 * @description: 秒杀活动
 * @author: kismet
 * @create: 2018-10-25 11:50
 */
public interface ISeckillActivityService extends BaseActivityService {

}
  • DiscountActivityServiceImpl 折扣活动实现类
/**
 * @description:
 * @author: kismet
 * @create: 2018-10-25 11:58
 */
@Service("discountActivityService")
public class DiscountActivityServiceImpl implements IDiscountActivityService {
    @Override
    public Long addActivity(ActivityVo vo) {
        System.out.println("折扣活动添加");
        return -1L;
    }

    @Override
    public void upDateActivity(ActivityVo vo) {
        System.out.println("折扣活动更新");
    }
}
  • SeckillActivityServiceImpl 秒杀活动实现类
/**
 * @description:
 * @author: kismet
 * @create: 2018-10-25 11:59
 */
@Service("seckillActivityService")
public class SeckillActivityServiceImpl implements ISeckillActivityService {

    @Override
    public Long addActivity(ActivityVo vo) {
        System.out.println("秒杀活动添加");
        return -2L;
    }

    @Override
    public void upDateActivity(ActivityVo vo) {
        System.out.println("秒杀活动更新");
    }
}

其他相关类

  • ActivityTypeEnum 活动类型枚举
/**
 * @description: 活动类型枚举
 * @author: kismet
 * @create: 2018-10-08 9:14
 */
@Getter
public enum ActivityTypeEnum {

    /**
     * 1,秒杀活动;service的key即为seckillActivityService
     */
    SECKILL(1, "秒杀活动", "seckillActivityService"),

    /**
     * 2,折扣活动;service的key即为discountActivityService
     */
    DISCOUNT(2, "折扣活动", "discountActivityService");

    private Integer key;

    private String desc;

    /**
     * 对应的service实现类key
     */
    private String service;

    ActivityTypeEnum(Integer key, String desc, String service) {
        this.key = key;
        this.desc = desc;
        this.service = service;
    }

    public static ActivityTypeEnum getEnumByType(Integer key) {
        for (ActivityTypeEnum item : ActivityTypeEnum.values()) {
            if (item.getKey().equals(key)) {
                return item;
            }
        }
        throw new RuntimeException("通过key获取枚举类异常");
    }
}
  • ActivityVo活动基本信息类
**
 * @description: 活动基本信息类
 * @author: kismet
 * @create: 2018-10-25 12:45
 */
@Getter
@Setter
public class ActivityVo {

    /**
     * 活动id
     */
    private Long id;
    /**
     * 活动类型:1,秒杀活动;2折扣活动
     */
    private Integer activityType;
}
  • MyTestController 测试类
/**
 * @description: 测试controller
 * @author: kismet
 * @create: 2018-10-25 12:54
 */
@RestController
public class MyTestController {

    //注入BaseActivityService子类的service,key为子类service的key
    @Autowired
    private Map<String,BaseActivityService> activityServiceMap;

    @RequestMapping("test")
    public void test(ActivityVo vo){
        vo.setActivityType(ActivityTypeEnum.SECKILL.getKey());//设置活动类型为直降测试用
        //1,根据活动对象获取活动类型,
        Integer activityType = vo.getActivityType();
        //2,获取活动对象的service的key
        String servicekey = ActivityTypeEnum.getEnumByType(activityType).getService();
        //3,获取对应的活动service
        BaseActivityService service = activityServiceMap.get(servicekey);
        //4,调用具体活动service的方法;add或者update等等
        service.addActivity(vo);
        service.upDateActivity(vo);
    }
}

测试和小结:

1> 测试

  • 当测试类中的vo的活动类型为1,秒杀活动时,
    即 vo.setActivityType(ActivityTypeEnum.SECKILL.getKey());
    控制台输出:

    秒杀活动添加
    秒杀活动更新

  • 当测试类中的vo的活动类型为1,秒杀活动时,控制台输出:
    即vo.setActivityType(ActivityTypeEnum.DISCOUNT.getKey());
    控制台输出:

    折扣活动添加
    折扣活动更新

小结:

  • 1>该策略方式借助于spring的ioc方式,将同一类型的bean注入到一个Map中
  • 2>将bean的id存到对应枚举中,
  • 3>通过活动的类型获取到具体的枚举,
  • 4>这样就可以通过枚举去得到bean的id,从而从Map中取到具体的bean
  • 5>然后再调用bean的方法
### Spring 框架中策略模式的应用场景 在 Spring 框架中,策略模式通过定义一组算法并将每个算法封装起来,使它们可以互换。这种设计使得应用程序可以在运行时动态选择合适的算法实现,而不必修改核心业务逻辑。 #### 策略接口与具体实现类 为了更好地理解如何在 Spring 中应用策略模式,下面是一个简单的示例: 假设有一个支付系统的应用场景,在该系统中有多种支付方式可以选择,比如信用卡支付、支付宝支付等。每种支付方式都可以看作是一种特定的策略。 ```java // 定义支付策略接口 public interface PaymentStrategy { void pay(double amount); } // 实现信用卡支付策略 @Component("creditCardPayment") public class CreditCardPayment implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("Paid " + amount + " using Credit Card."); } } // 实现支付宝支付策略 @Component("alipayPayment") public class AlipayPayment implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("Paid " + amount + " using Alipay."); } } ``` 上述代码展示了不同类型的支付策略是如何作为独立组件注册到 Spring 容器中的[^1]。 #### 使用依赖注入选择策略 接下来展示如何基于用户输入或其他条件来决定使用哪种支付方式进行交易处理: ```java @Service public class OrderService { private final Map<String, PaymentStrategy> paymentStrategies; @Autowired public OrderService(List<PaymentStrategy> strategies) { this.paymentStrategies = strategies.stream() .collect(Collectors.toMap(PaymentStrategy::getId, Function.identity())); } public void processOrder(String strategyId, double amount) { PaymentStrategy selectedStrategy = paymentStrategies.get(strategyId); if (selectedStrategy != null) { selectedStrategy.pay(amount); } else { throw new IllegalArgumentException("Unknown payment method"); } } } ``` 在这个例子中,`OrderService` 类负责接收订单并调用相应的支付服务完成付款操作。这采用了构造函数注入的方式获取所有的 `PaymentStrategy` 实现,并将其存储在一个映射表以便后续查找和调用[^2]。 #### 配置文件支持灵活切换策略 除了编程式的策略选择外,还可以借助于 Spring 的配置机制让开发者能够更方便地管理各种策略之间的转换关系。例如,可以通过 XML 或者 Java Config 来指定默认使用的支付手段,甚至可以根据环境变量自动调整行为。 ```yaml payment.default-strategy: alipayPayment ``` 当需要改变默认支付方式时只需简单更改此属性即可生效,无需重新编译源码或部署新版本软件。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值