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);
}
}

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

  1. 如何写出面试官欣赏的Java单例

    单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例. 今天我们不谈单例模式的用途,只说一说如果在面试的时候面试官让你敲一段代码 ...

  2. 类(静态)变量和类(静态)static方法以及main方法、代码块,final方法的使用,单例设计模式

    类的加载:时间 1.创建对象实例(new 一个新对象时) 2.创建子类对象实例,父类也会被加载 3.使用类的静态成员时(静态属性,静态方法) 一.static 静态变量:类变量,静态属性(会被该类的所 ...

  3. golang写业务代码,用全局函数还是成员函数

    在golang中,函数划分为全局函数和成员函数,在使用的时候,有种情况,会产生一些疑惑的,就是在写业务代码的时候,使用全局函数好像会比较方便,一般业务代码,都不会复用,都是针对特定的业务进行编程,要复 ...

  4. jdk1.7推出的Fork/Join提高业务代码处理性能

    jdk1.7推出的Fork/Join提高业务代码处理性能 jdk1.7之后推出了Fork/Join框架,其原理个人理解为:递归多线程并发处理业务代码,以下为我模拟我们公司业务代码做的一个案例,性能可提 ...

  5. 朱晔的互联网架构实践心得S2E2:写业务代码最容易掉的10种坑

    我承认,本文的标题有一点标题党,特别是写业务代码,大家因为没有足够重视一些细节最容易调的坑(侧重Java,当然,本文说的这些点很多是不限制于语言的). 1.客户端的使用 我们在使用Redis.Elas ...

  6. 朱晔的互联网架构实践心得S2E1:业务代码究竟难不难写?

    注意,这是我的架构实践心得的第二季的系列文章,第一季有10篇你也可以回顾. 见https://www.cnblogs.com/lovecindywang/category/1296779.html 最 ...

  7. .net程序员写业务代码需要注意的地方

    代码规范要求1.命名空间规范:dao层的impl实现和接口采用一样的命名空间,到对应文件夹层:IxxDaoContext与其实现类采用顶级命名空间. 2.TableEntity文件夹:所有的实体放到各 ...

  8. CSDN日报20170413 ——《天天写业务代码的那些年,我们是怎样成长过来的》

    [程序人生]天天写业务代码的那些年,我们是怎样成长过来的 作者:Phodal 比起写业务代码更不幸的是,主要工作是修 Bug , bug , buG , bUg. [Java 编程]Springboo ...

  9. 读 Kafka 源码写优雅业务代码:配置类

    这个 Kafka 的专题,我会从系统整体架构,设计到代码落地.和大家一起杠源码,学技巧,涨知识.希望大家持续关注一起见证成长! 我相信:技术的道路,十年如一日!十年磨一剑! 往期文章 Kafka 探险 ...

随机推荐

  1. mysql float和decimal

    结论: 1. float 默认只保存6位(除去小数点),如果超过6位,则四舍五入,所以float存储的数据是不精确的,只是近似值: 2. decimal,如果输入的数据超过了定义的最大值,那么则溢出, ...

  2. Linux(Redhat)传送门汇总

    Linux(Redhat)传送门汇总 linux 环境布置 常用命令与shell 常用命令 shell 环境布置 Linux虚拟机安装(rhel 7.4) 虚拟机网络设置 VMware虚拟机开机启动 ...

  3. nuxt build 项目文件分析、nuxt build 发布后的资源如何部署cdn

    建议在项目发布的时候,还是将.nuxt 进行发布到生产环境,是比较稳妥的做法 出处:https://nickfu.com/p/150 nuxt build 后的前端资源都会存放在.nuxt/dist/ ...

  4. JQuery系列(8) - JQuery插件开发

    所谓“插件”,就是用户自己新增的jQuery实例对象的方法.由于该方法要被所有实例共享,所以只能定义在jQuery构造函数的原型对象(prototype)之上.对于用户来说,把一些常用的操作封装成插件 ...

  5. Go语言 - 结构体 | 方法

    自定义类型和类型别名 自定义类型 在Go语言中有一些基本的数据类型,如string.整型.浮点型.布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型. 自定义类型是定义了一个全新的类型 ...

  6. Virtual DOM的渲染机制--猜测

    一个node的状态发生变化: 会对当前结点和子节点的数据全部进行更新: 然后进行dom比较: 比较完毕后一次性提交: 相对于以前的渲染方式: 每一个node的数据发生变化,都会产生一次渲染提交: 以上 ...

  7. Codechef July Challenge 2019 Snake and Apple Tree

    费用流.把每个方格拆成 $T$ 个点,$t$ 时刻一个方格向周围四个方格的 $t + 1$ 的点连一条容量为 $1$ 费用为 $0$ 的边,向自身的 $t + 1$ 连一条容量为 $1$ 费用为该方格 ...

  8. JS的ES6的Symbol

    一.Symbol 1.什么是Symbol: Symbol是ES6新添加的原始类型(ES5已有原始数据类型:String,Number,boolean,function,undefined,object ...

  9. C# VS常用操作

    VS点击项目,就会打开文件,其实我只是想选中而已, 在这个地方可以改. 原文:https://blog.csdn.net/yellowegg/article/details/12217309

  10. A1128 | 逻辑想象能力、简洁高效美观的代码、memset的使用情景

    写了三遍才AC,这真是对智商极大的侮辱 C++代码: #include <stdio.h> #include <memory.h> #include <math.h> ...