背景
根据优惠券类型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("红包"));
}