写点什么

工厂 + 策略在 springboot 项目中的使用场景

  • 2023-05-28
    湖南
  • 本文字数:2069 字

    阅读完需:约 7 分钟

业务场景

我们需要做一个报表,前端传进不同的类型,需要去数据库中不同的表格去查找,将数据展示出来。也就是说,虽然是不同数据库的表,但是因为数据结构是一样的,所以我们只需要提供一个接口给前端,返回相同的数据结构。后端需要做的事情,就是根据不同的类型去不同的数据库表中查找数据,拼接成一个视图对象返回给前端。

解决方案

  1. 在业务层使用 if-else 判断类型,去不同的数据表中查找。

  2. 使用工厂模式结合策略模式,再使用注解来选择不同的策略,实现不同的业务逻辑。


我们选用的是第二种方式。

代码示例

定义枚举

@AllArgsConstructor@Getterpublic enum SaleOrderEnum {
SHOP_SALE_ORDER("10001", "门店销售单"), SUPPLY_SALE_ORDER("10002","供应链销售单");
public static SaleOrderEnum findByCode(String code) { for (SaleOrderEnum orderEnum : SaleOrderEnum.values()) { if (orderEnum.getCode().equals(code)) { return orderEnum; } } throw new IllegalArgumentException("code is invalid"); }
private String code;
private String name;}
复制代码

定义注解

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface OrderStrategyType {    SaleOrderEnum orderType();}
复制代码

我定义这个注解的目的,是在不同的策略上使用的,在工厂中就可以根据注解查找到所有的策略,并保存进 map 中一一对应起来,一旦有参数进来,就去 map 中去查找对应的策略,就可以执行对应的方法了。

定义抽象的策略类

public abstract class OrderStrategy {    public abstract List<Object> queryList();}
复制代码

定义具体的策略实现

@Slf4j@Component@RequiredArgsConstructor@OrderStrategyType(orderType = SaleOrderEnum.SHOP_SALE_ORDER)public class ShopSaleOrderStrategy extends OrderStrategy {
@Override public List<Object> queryList() { log.info("查询门店销售单列表......"); return Arrays.asList("门店销售单1","门店销售单2","门店销售单3"); }}
复制代码


@Slf4j@Component@RequiredArgsConstructor@OrderStrategyType(orderType = SaleOrderEnum.SUPPLY_SALE_ORDER)public class SupplySaleOrderStrategy extends OrderStrategy {    @Override    public List<Object> queryList() {        log.info("查询供应链销售单列表......");        return Arrays.asList("供应链销售单1","供应链销售单2");    }}
复制代码

注意,我们是要把我们具体的策略交给 spring 管理,所以我们加上了 @Service 注解。

定义工厂类

@Component@RequiredArgsConstructorpublic class OrderStrategyFactory {
/** * spring会帮我们注入所有OrderStrategy的子类 */ private final List<OrderStrategy> strategyList;
private static Map<SaleOrderEnum, OrderStrategy> map = new ConcurrentHashMap<>();
public static OrderStrategy getStrategy(String code){ return map.get(SaleOrderEnum.findByCode(code)); }
@PostConstruct public void init(){ strategyList.forEach(i -> { OrderStrategyType annotation = AnnotationUtils.findAnnotation(i.getClass(), OrderStrategyType.class); map.put(annotation.orderType(),i); }); }}
复制代码

因为上面我们已经把具体的策略,像 supplySaleOrderStrategy、shopSaleOrderStrategy 这些策略的实现,交给 spring 管理了,也就是说我们可以从 spring 的容器中获取到对应的 bean,当然也可以进行依赖注入。


所以在工厂类中,我们定义了一个 strategyList 属性,并且使用 @RequiredArgsConstructor 注解,就是使用构造器的方式将属性注入。所以当 spring 容器启动的时候,就会查找所有策略,并注入到工厂类的属性当中。这是 spring 的依赖注入的原理。


我们使用 @PostContruct 注解,当工厂类加载完毕之后,就会执行 init()方法。这时候,因为 orderStrategyFactory 这个 bean 已经在 spring 容器中加载完毕了,并且也注入了属性,所以这个 strategyList 就有值了,我们可以遍历这个列表,获取到对应 OrderStrategyType 这个注解的信息,然后放入到 map 当中,后面我们就可以根据枚举类型将不同的策略对应起来了。

定义 controller

@RestController@RequestMapping("/test")public class TestController {
@RequestMapping("/getList") public List<Object> getList(@RequestParam String type){ OrderStrategy strategy = OrderStrategyFactory.getStrategy(type); return strategy.queryList(); }}
复制代码

总结

这样,一旦我们有加入其它表的查询,但是返回给前端的数据结构是一样的,我们就可以在枚举类中加入对应的类型,在具体的策略实现类中加入注解,并指定对应的枚举类型,这样我们就可以完成我们的业务需求了。


作者:人生密密缝

链接:https://juejin.cn/post/7236217091967008826

来源:稀土掘金

用户头像

还未添加个人签名 2021-07-28 加入

公众号:该用户快成仙了

评论

发布
暂无评论
工厂+策略在springboot项目中的使用场景_Java_做梦都在改BUG_InfoQ写作社区