背景
根据优惠券类型resourceType -> 确定查询哪个数据表
根据编码resourceId -> 到对应的数据表里边查询优惠券的派发方式grantType和领取规则
优惠券有多种类型,分别对应了不同的数据库表:
红包 —— 红包发放规则表
购物券 —— 购物券表
QQ会员
外卖会员
实际的优惠券远不止这些,这个需求是要我们写一个业务分派的逻辑
首先能想到的思路就是if-else或者switch case:
public String getNameByType(String resourceType) {
if ("红包".equals(resourceType)) {
return "每周末9点发放";
} else if ("购物券".equals(resourceType)) {
return "每周三9点发放";
} else if ("qq会员".equals(resourceType)) {
return "每周一0点开始秒杀";
} else {
return "查询不到该优惠券的发放方式";
}
}
如果要这么写的话, 一个方法的代码可就太长了,影响了可读性。(别看着上面case里面只有一句话,但实际情况是有很多行的)
而且由于整个 if-else 的代码有很多行,也不方便修改,可维护性低。
策略模式
策略模式是把if语句里面的逻辑抽出来写成一个类,如果要修改某个逻辑的话,仅修改一个具体的实现类的逻辑即可,可维护性会好不少。
- 策略类的公共抽象类
public abstract class AbsStragegy {
//定义支持所有算法的公共接口
public abstract String query();
}
- 策略类的具体实现
RedPaper
public class RedPaper extends AbsStragegy{
/**
* 查询红包的
*
* @return {@link String}
*/
@Override
public String query() {
return "每周末9点发放";
}
}
Shopping
public class Shopping extends AbsStragegy{
/**
* 购物券的发放方式
*
* @return {@link String}
*/
@Override
public String query() {
return "每周三9点发放";
}
}
QQVip
public class QQVip extends AbsStragegy {
/**
* qq会员的发放方式
*
* @return {@link String}
*/
@Override
public String query() {
return "每周一0点开始秒杀";
}
}
- 客户端调用的接口
public class Context {
AbsStragegy absStragegy;
public Context(AbsStragegy absStragegy){
this.absStragegy=absStragegy;
}
public String ContextQuery(){
return this.absStragegy.query();
}
}
策略模式的实现
public String getNameByType2(String type) {
switch (type) {
case "红包" -> {
Context context = new Context(new RedPaper());
return context.ContextQuery();
}
case "购物券" -> {
Context context = new Context(new Shopping());
return context.ContextQuery();
}
case "qq会员" -> {
Context context = new Context(new QQVip());
return context.ContextQuery();
}
default -> {
return "查询不到该优惠券的发放方式";
}
}
}
缺点明显:
如果 if-else的判断情况很多,那么对应的具体策略实现类也会很多,上边的具体的策略实现类还只是3个,查询红包发放方式写在类RedPaper里边,购物券写在另一个类Shopping里边;那资源类型多个QQ会员和外卖会员,不就得再多写两个类?有点麻烦了
没法俯视整个分派的业务逻辑
Map+函数式接口
用上了Java8的新特性lambda表达式
判断条件放在key中
对应的业务逻辑放在value中
这样子写的好处是非常直观,能直接看到判断条件对应的业务逻辑
需求:根据优惠券(资源)类型 resourceType 和编码 resourceId 查询派发方式grantType
代码:
查询类
public class GrantTypeSerivce {
public String redPaper(String resourceId){
//红包的发放方式
return "每周末9点发放";
}
public String shopping(String resourceId){
//购物券的发放方式
return "每周三9点发放";
}
public String QQVip(String resourceId){
//qq会员的发放方式
return "每周一0点开始秒杀";
}
}
public class QueryGrantTypeService {
private GrantTypeSerivce grantTypeSerivce = new GrantTypeSerivce();
private Map<String, Function<String, String>> grantTypeMap = new HashMap<>();
public void dispatcherInit() {
grantTypeMap.put("红包", resourceId -> grantTypeSerivce.redPaper(resourceId));
grantTypeMap.put("购物券", resourceId -> grantTypeSerivce.shopping(resourceId));
grantTypeMap.put("qq会员", resourceId -> grantTypeSerivce.QQVip(resourceId));
}
public String getResult(String resourceType) {
//Controller根据 优惠券类型resourceType、编码resourceId 去查询 发放方式grantType
Function<String, String> result = grantTypeMap.get(resourceType);
if (result != null) {
//传入resourceId 执行这段表达式获得String型的grantType
return result.apply(resourceType);
}
return "查询不到该优惠券的发放方式";
}
主函数
public static void main(String[] args) {
QueryGrantTypeService service = new QueryGrantTypeService();
service.dispatcherInit();
System.out.println(service.getResult("红包"));
}
文章讨论了如何改进优惠券派发逻辑的代码结构,从原始的if-else语句转变为使用策略模式和Java8的Lambda表达式,以提高代码的可读性和可维护性。通过创建抽象策略类和具体策略实现,以及使用Map和函数式接口,使得业务逻辑更加清晰直观。

908

被折叠的 条评论
为什么被折叠?



