如何将业务代码写得像诗一样(使用注解+单例+工厂去掉一大波if和else判断)

1.订单控制器,提供一个根据商品id和银行渠道id计算商品折后价格的接口:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;

@RestController
@RequestMapping("/order")
public class OrderController {

    /**
     * 根据商品id和银行渠道id计算折扣后的金额
     *
     * @param goodsId   商品id
     * @param channelId 银行渠道id
     * @return
     */
    @GetMapping("/calc")
    @ResponseBody
    public String calcAmount(Integer goodsId, Integer channelId) {
        Context context = new Context();
        BigDecimal bigDecimal;
        try {
            bigDecimal = context.calRecharge(goodsId, channelId);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        return bigDecimal.setScale(2) + "";
    }
}

 

2.上下文:

import java.math.BigDecimal;

public class Context {

    /**
     * 根据商品id和银行渠道id计算折扣后的金额
     *
     * @param goodsId   商品id
     * @param channelId 银行渠道id
     * @return
     * @throws Exception
     */
    public BigDecimal calRecharge(Integer goodsId, Integer channelId) throws Exception {
        StrategyFactory strategyFactory = StrategyFactory.getInstance();
        // 根据渠道id查询具体的银行实现类
        Strategy strategy = strategyFactory.create(channelId);
        // 调用具体的实现类进行计算
        return strategy.calRecharge(goodsId, channelId);
    }
}

 

3.折扣计算单例工厂类,内部用一个Map来存储银行渠道id和具体银行实现类之间的映射关系,方便根据渠道id反射获取对应银行具体的实现类:

import org.reflections.Reflections;

import java.util.HashMap;
import java.util.Set;

public class StrategyFactory {
    private static StrategyFactory strategyFactory = new StrategyFactory();

    private StrategyFactory() {
    }

    public static StrategyFactory getInstance() {
        return strategyFactory;
    }

    private static HashMap<Integer, String> source_map = new HashMap<>();

    static {
        Reflections reflections = new Reflections("ICBCBankImpl");
        Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(Pay.class);
        for (Class<?> clazz : classSet) {
            Pay pay = clazz.getAnnotation(Pay.class);
            source_map.put(pay.channelId(), clazz.getCanonicalName());
        }
    }

    /**
     * 根据银行渠道id从Map中获取具体的银行实现类
     *
     * @param channelId
     * @return
     * @throws Exception
     */
    public Strategy create(int channelId) throws Exception {
        String clazz = source_map.get(channelId);
        Class<?> clazz_ = Class.forName(clazz);
        return (Strategy) clazz_.newInstance();
    }
}

 

4.计算折后价格的接口:

import java.math.BigDecimal;

public interface Strategy {
    BigDecimal calRecharge(Integer goodsId, Integer channelId);
}

 

5.工商银行实现类,类上加上@Pay注解指定工商银行对应的数据库中的渠道id:

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * 工商银行实现类,对应的数据库中的渠道id为1
 */
@Pay(channelId = 1)
public class ICBCBankImpl implements Strategy {

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private ChannelMapper channelMapper;

    /**
     * 根据商品id和银行渠道id计算优惠后的价格
     *
     * @param goodsId   商品id
     * @param channelId 银行渠道id
     * @return
     */
    @Override
    public BigDecimal calRecharge(Integer goodsId, Integer channelId) {
        BigDecimal goodsPrice = goodsMapper.getGoodsPriceById(goodsId);
        BigDecimal discountPrice = channelMapper.getDiscountPriceById(channelId);
        if (goodsPrice == null || discountPrice == null) {
            return null;
        }
        return goodsPrice.multiply(discountPrice);
    }
}

 

6.用于标记银行实现类的注解,定义了一个银行渠道id属性:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pay {
    int channelId();
}

 

7.模拟查询商品价格的Dao:

import java.math.BigDecimal;

public class GoodsMapper {
    public BigDecimal getGoodsPriceById(Integer goodsId) {
        return BigDecimal.valueOf(599);
    }
}

 

8.模拟查询查询渠道优惠折扣的Dao:

import java.math.BigDecimal;

public class ChannelMapper {
    public BigDecimal getDiscountPriceById(Integer channelId) {
        return BigDecimal.valueOf(0.5);
    }
}

 

posted @ 2019-11-04 22:43  xuebusi  阅读(658)  评论(1编辑  收藏  举报