注解策略方式替換 if-else

策略模式:

介绍
定义一系列算法,然后将每一个算法封装起来,并将它们可以互相替换。也就是将一系列算法封装到一系列策略类里面。策略模式是一种对象行为型模式。详细介绍可参阅:[策略模式Strategy](https://blog.csdn.net/hguisu/article/details/7558249/)
适用性
用于处理相同场景下不同对象(类型)不同而具体处理业务逻辑有差异。我们往往会使用if...else或者switch-case语句,会造成代码可读性变差。所以将这些处理方式,组合构成算法策略族,它们的共性,体现在策略接口行为上,消除一些if else条件语句。
策略模式的角色:
环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的具体算法或行为。

注解实现:

业务场景:
	假设有这么一个场景,订单可以根据产品类型做活动比如 打折,每个产品的
打折情况不一样(实际场景应该根据配置处理即可,此处仅作为一种思路)。比如:电脑打6折,手机打8.2折,电视7.6折等。
定义枚举:
定义一个电子产品类型枚举:ElectronicEnum
/**
 * @author xuan
 * @version 1.0.0
 * @Description 电子产品类型
 * @createTime 2022年01月02日 14:46
 */
public enum ElectronicEnum {
    CELLPHONE("001","手机"),
    COMPUTER("002","电脑"),
    TV("003","电视");

    private String type;
    private String desc;
    public String getType() {
        return type;
    }
    public String getDesc() {
        return desc;
    }
    /**
     *
     * @param type
     * @param desc
     */
    ElectronicEnum(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
}
自定义注解
我们写一个注解 ElectronicType,该注解用在实现类上,表名该类代表的是何种电子产品类型
/**
 * @author xuan
 * @version 1.0.0
 * @Description 电子产品类型注解
 * @createTime 2022年01月02日 14:45
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ElectronicType {
    /**
     * 策略类型
     * @return
     */
    ElectronicEnum value();
}
定义策略接口:
定义电子产品业务接口:ElectronicProductService
/**
 * @author xuan
 * @version 1.0.0
     * @Description 电子产品业务
 * @createTime 2022年01月02日 14:56
 */
public interface ElectronicProductService {
    /**
     * 打折
     * @param params 业务参数
     * @return
     */
    String discount(String params);
     /**
     * 满减活动
     * @param orderVo 业务参数
     * @return
     */
    OrderVo fullReduction(OrderVo orderVo);
 }
业务实现
	我们根据3中产品类型编写3个实现类,电脑、电视、手机。
关键点在于实现类上添加上我们自定义的注解
 @ElectronicType(ElectronicEnum.COMPUTER)
 其中注解元素值为各个类型枚举,如以下:

1.电脑类型实现类:ComputerServiceImpl

/**
 * @author xuan
 * @version 1.0.0
 * @Description 电脑
 * @createTime 2022年01月02日 14:58
 */
@Slf4j
@Component
@ElectronicType(ElectronicEnum.COMPUTER)
public class ComputerServiceImpl implements ElectronicProductService {
    @Override
    public String discount(String params) {
        // 具体的业务逻辑
        return "电脑 打6折";
    }

    @Override
    public OrderVo fullReduction(OrderVo orderVo) {

        OrderVo orderVo1 = new OrderVo();
        BeanUtils.copyProperties(orderVo,orderVo1);
        log.info("电视:满2200减25");
        // 赋值 模拟业务 显示
        orderVo1.setProductName("电脑");
        orderVo1.setRemark("满2200减25");
        orderVo1.setPayAmt(orderVo.getOrderAmt());
        orderVo1.setDiscountAmt(new BigDecimal("0"));

        if (orderVo.getOrderAmt().compareTo(new BigDecimal("2200"))==1){
            BigDecimal discountAmt=new BigDecimal("25");
            orderVo1.setDiscountAmt(discountAmt);
            orderVo1.setPayAmt(orderVo.getOrderAmt().subtract(discountAmt));
        }

        return orderVo1;
    }

}

2.手机类型实现类:MobilePhoneServiceImpl


/**
 * @author xuan
 * @version 1.0.0
 * @Description 手机
 * @createTime 2022年01月02日 14:59
 */
@Slf4j
@Component
@ElectronicType(ElectronicEnum.CELLPHONE)
public class MobilePhoneServiceImpl  implements ElectronicProductService {
    @Override
    public String discount(String params) {
        // 具体的业务逻辑
        return "手机打8.2折";
    }

    @Override
    public OrderVo fullReduction(OrderVo orderVo) {
        OrderVo orderVo1 = new OrderVo();
        BeanUtils.copyProperties(orderVo,orderVo1);
        log.info("电视:满500减15");
        // 赋值 模拟业务 显示
        orderVo1.setProductName("手机");
        orderVo1.setRemark("满500减15");
        orderVo1.setPayAmt(orderVo.getOrderAmt());
        orderVo1.setDiscountAmt(new BigDecimal("0"));

        if (orderVo.getOrderAmt().compareTo(new BigDecimal("500"))==1){
            BigDecimal discountAmt=new BigDecimal("15");
            orderVo1.setDiscountAmt(discountAmt);
            orderVo1.setPayAmt(orderVo.getOrderAmt().subtract(discountAmt));
        }
        return orderVo1;
    }
}

3.电视类型实现类:MobilePhoneServiceImpl

/**
 * @author xuan
 * @version 1.0.0
 * @Description 电视
 * @createTime 2022年01月02日 15:00
 */
@Slf4j
@Component
@ElectronicType(ElectronicEnum.TV)
public class TVServiceImpl  implements ElectronicProductService {
    @Override
    public String discount(String params) {
        // 业务...
        return "电视7.6折";
    }

    /**
     * 满减
     * @param orderVo 业务参数
     * @return
     */
    @Override
    public OrderVo fullReduction(OrderVo orderVo) {
        OrderVo orderVo1 = new OrderVo();
        BeanUtils.copyProperties(orderVo,orderVo1);
        log.info("电视:满满1000减20");
        // 赋值 模拟业务 显示
        orderVo1.setProductName("电视");
        orderVo1.setRemark("满满1000减20");
        orderVo1.setPayAmt(orderVo.getOrderAmt());
        orderVo1.setDiscountAmt(new BigDecimal("0"));

        if (orderVo.getOrderAmt().compareTo(new BigDecimal("1000"))==1){
            BigDecimal discountAmt=new BigDecimal("20");
            orderVo1.setDiscountAmt(discountAmt);
            orderVo1.setPayAmt(orderVo.getOrderAmt().subtract(discountAmt));
        }

        return orderVo1;
    }
}
策略接口实现类工厂
启动时加载电子产品业务所有因子,将所有的实现类根据类型封装到enumElectronicProductServiceMap变量中,
根据产品类型获取对应的实现类。
1.实现sping bean上下文
implements  ApplicationContextAware 
2.定义变量
private static Map<ElectronicEnum, ElectronicProductService> enumElectronicProductServiceMap;
3.自动加载所有因子组实现类
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 获取 ElectronicProductService 接口的所有实现类
        Map<String,ElectronicProductService> electronicProductServiceMap=applicationContext.getBeansOfType(ElectronicProductService.class);
        enumElectronicProductServiceMap = new HashMap<>();

        // 将实现类放入map中,key为实现类对应的枚举,value为实现类
        for (ElectronicProductService item: electronicProductServiceMap.values()) {
            ElectronicType annotation = item.getClass().getAnnotation(ElectronicType.class);
            if (null != annotation ){
                enumElectronicProductServiceMap.put(annotation.value(),item);
            }

        }
    }
4.定义实现类方法
/**
     * 获取实现类
     * @param type
     * @return electronicProductService
     * @throws BusException
     */
    public static ElectronicProductService getElectronicProductServiceImpl(String type) throws BusException {
        return enumElectronicProductServiceMap.get(getElectronicEnum(type));
    }

    public static ElectronicEnum getElectronicEnum(String type){
        for (ElectronicEnum item: ElectronicEnum.values()) {
            if (item.getType().equals(type)){
                return item;
            }
        }
        throw  new BusException("401","服务不存在!");
    }
5:完整代码
/**
 * @author xuan
 * @version 1.0.0
 * @Description ElectronicProductService 接口实现类
 * @createTime 2022年01月21日 10:51
 */
@Component
@Slf4j
public class ElectronicProductServiceFactory implements  ApplicationContextAware {

    /** 存所有 ElectronicProductService 实现类 */
    private static Map<ElectronicEnum, ElectronicProductService> enumElectronicProductServiceMap;


    /**
     * 自动加载所有因子组实现类
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 获取 ElectronicProductService 接口的所有实现类
        Map<String,ElectronicProductService> electronicProductServiceMap=applicationContext.getBeansOfType(ElectronicProductService.class);
        enumElectronicProductServiceMap = new HashMap<>();

        // 将实现类放入map中,key为实现类对应的枚举,value为实现类
        for (ElectronicProductService item: electronicProductServiceMap.values()) {
            ElectronicType annotation = item.getClass().getAnnotation(ElectronicType.class);
            if (null != annotation ){
                enumElectronicProductServiceMap.put(annotation.value(),item);
            }

        }
    }


    /**
     * 获取实现类
     * @param type
     * @return electronicProductService
     * @throws BusException
     */
    public static ElectronicProductService getElectronicProductServiceImpl(String type) throws BusException {
        return enumElectronicProductServiceMap.get(getElectronicEnum(type));
    }

    public static ElectronicEnum getElectronicEnum(String type){
        for (ElectronicEnum item: ElectronicEnum.values()) {
            if (item.getType().equals(type)){
                return item;
            }
        }
        throw  new BusException("401","服务不存在!");
    }
}

电子商品业务策略
	该类(ElectronicProductServiceStrategy)呢也是去实现
ElectronicProductService 接口,该实现类和前面3个实现类不同在于,
该实现方法不写具体业务逻辑而是根据 产品类型去调用前面3种实现类,
从而达到每个实现类只需关注自己业务逻辑,代码解耦;
此类上不写我们自定义的注解而是加上另一个注解@Primary;
这样在调用ElectronicProductService 接口时自动调用该实现类。

1:ElectronicProductServiceStrategy实现类


/**
 * @author xuan
 * @version 1.0.0
 * @Description 电子商品业务策略
 * @createTime 2022年01月02日 15:06
 */
@Slf4j
@Primary
@Component
public class ElectronicProductServiceStrategy implements ElectronicProductService {
    /**
     * 打折
     * @param type
     * @return
     */
    @Override
    public String discount(String type) {
        ElectronicProductService electronicProductService=ElectronicProductServiceFactory.getElectronicProductServiceImpl(type);
        return electronicProductService.discount("这是参数");
    }
    /**
     * 满减
     * @param orderVo 业务参数
     * @return
     */
    @Override
    public OrderVo fullReduction(OrderVo orderVo) {
        ElectronicProductService electronicProductService=ElectronicProductServiceFactory.getElectronicProductServiceImpl(orderVo.getType());
        return electronicProductService.fullReduction(orderVo);
    }

}

2.调用

构造注入ElectronicProductService ,此处实际首先调用的实现类是:
ElectronicProductServiceStrategy ,因为我们加了注解@Primary

    private final ElectronicProductService electronicProductService  ;
    public ElectronicProductController( ElectronicProductService electronicProductService){
        this.electronicProductService=electronicProductService;
    }

3.完整类

/**
 * @author xuan
 * @version 1.0.0
 * @Description 干掉 IF ELSE的 第一种模式
 * @createTime 2022年01月02日 15:01
 */
@Slf4j
@RestController
@RequestMapping("/order")
public class ElectronicProductController {
//    @Resource
//    private   ElectronicProductService electronicProductService  ;

    private final ElectronicProductService electronicProductService  ;
    public ElectronicProductController( ElectronicProductService electronicProductService){
        this.electronicProductService=electronicProductService;
    }


    /**
     * 打折
     * @param type
     * @return
     */
    @ResponseBody
    @RequestMapping("/discount/{type}")
    public Object discount(@PathVariable String type){
        return electronicProductService.discount(type);
    }

    /**
     * 优惠
     * @param type
     * @return
     */
    @ResponseBody
    @RequestMapping("/fullReduction/{type}")
    public Object fullReduction(@PathVariable String type){
        OrderVo orderVo = new OrderVo();
        orderVo.setType(type);
        orderVo.setOrderAmt(getBigDecimalF2(5000));
        orderVo.setOrderId(UUID.randomUUID().toString().toLowerCase().replace("-",""));

        OrderVo reOrderVo = electronicProductService.fullReduction(orderVo);

        return Result.sucess(reOrderVo);
    }


    public BigDecimal getBigDecimalF2(int max){
        Double rand=Math.random()*max;
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        String randDec=decimalFormat.format(rand);
        return new BigDecimal(randDec);
    }

}

测试
执行main方法,浏览器输入
http://127.0.0.1:1800/order/discount/001  输出:手机打8.2折
http://127.0.0.1:1800/order/discount/002 输出:电脑 打6折
http://127.0.0.1:1800/order/discount/003  输出:电视7.6折
符合我们的预期,至此消除了if-esle(switch-case)语句块

项目演示demo源码

github: https://github.com/xuanzhiyigit/ifelse

gitee: https://gitee.com/xuanzhiyi/ifelse





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值