开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
现实
比如你参与的某个活动中、你高高兴兴的去参加活动、你刚进入到页面发现他弹出来一个“仅限xxx参与活动”、然后引导你去另一个活动、发现另一个活动能进入到页面中、就当你高高兴兴点击领取薅它羊毛的时候、那个加载圈在哪转啊转啊!!!结果它又弹出一个“您当前会员等级不符合领取条件限制”。
就是很多时候、当你参与的时候会校验你的一些身份信息、符不符合条件之类的、假设让你搞一套通用的活动限制、领取礼品的限制、你总不可能每个活动都去写一套之前写过的条件限制、加一堆if else
、这样是很不合理的。
场景简介
假设我有一个活动、要限制参与人的条件限制、如:某某会员能参加、后续会有多个活动、每个活动需要配置不同的限制、活动中的礼品也符合条件限制的人才能领取到。
限制统一由配置化、如:是否VIP、是否多少多少级会员能参与、无非就两种、一个单选、一个多选限制满足
或者活动层面在加一个限制条件是”全部满足“或者”任意满足“条件、判断是活动的全部限制。
基本的话以上这些就可以满足了、但是条件苛刻的话可以在多选的层面在加一个、“并且”、“或者”。
由以上这些条件就能设想一个活动限制、而这些限制要单独拎出来、由每个活动来配置需要限制条件。
开始实现
如果没有开始设计之前、肯定都是少量的判断配置、如是不是会员之类、最简单最快的方式就在指定的地方手动写代码配置需要的限制。
举个栗子、如进入页面的时候我要判断是不是会员.....等一些其他限制。
@RequestMapping("index")
public String index() {
if("限制会员的值" != "我的会员"){
System.out.println(”不是会员、不能进入页面“);
}else if("限制xxxx的值" != "我的xxx"){
System.out.println(”不是xxx、不能进入页面“);
}else{
System.out.println(”通过限制“);
}
return "free_activities/index";
}
可以看出写一堆的if的判断、前期可能大部分人都是这样写、但是活动页面一旦多起来、就粘贴一堆重复的东西(你也想写10多个if else嘛??)、这些还不算什么、如果一些限制的值的枚举需要改之类的这种才要命、一堆活动都要你一个一个改、已经可以看出两个问题了1、大量if else 2、活动限制的值写死。
解决if else...
无非就是用一些设计模式中的一些思路、首先定义一个接口、由各种限制的实现类去实现这个接口并重写这个接口中的方法、使用起来就可以去根据对应限制的类型去找到对应限制的实现方法、说句人话就是回家各找各妈。
/**
* 活动限制
* @param <LimitType> 限制数据的类型
*/
public interface LimitAdapter<LimitType> {
/**
* 是否进行要进行逻辑处理。
* @return true 无限制跳过操作、false 有限制
*/
Boolean isNotMust();
/**
* 得到限制的值
* @return 限制的value值
*/
LimitType getLimitValue();
/**
* 执行处理【用户是否符合限制】
* @return true 符合、false 不符合。
*/
Boolean execute();
}
上面也看了、这种限制无非就单选或者多选限制、所以可以在抽象出一个单选处理类、以及一个多选处理的类
public abstract class SingleLimit implements LimitAdapter<Integer> {
/**
* 是否限制、做为排除使用、因为限制的值为空就证明不用校验。
* @return true 不限制、false 限制
*/
@Override
public Boolean isNotMust() {
return null == getLimitValue();
}
}
public abstract class MultiLimit implements LimitAdapter<List<String>> {
/**
* 是否限制、做为排除使用、因为限制的值为空就证明不用校验
* @return true 不限制、false 限制
*/
@Override
public Boolean isNotMust() {
return null == getLimitValue();
}
}
因为没有很复杂的处理、在isNotMust
方法中只做了判断空的操作、接下来就是看各种限制的实现。
掘金会员实现类
@Slf4j
public class Vip extends SingleLimit {
/**
* 得到配置的限制、我们这边写死了限制的值
* @return 限制值
*/
@Override
public Integer getLimitValue() {
return 1;
}
/**
* 处理用户是否是会员
* @return true 是会员、false不是会员。
*/
@Override
public Boolean execute() {
// 拿到当前用户、可以通过第三方或者本地库获取用户会员信息
Account account = AccountContext.getAccount();
// 拿到当前的限制值
Integer limitValue = getLimitValue();
if (!Objects.equals(limitValue, account.getIsVip())) {
log.error("校验用户:[{}]是否会员异常、限制的值:[{}]、用户会员信息:[{}]", account.getId(), limitValue, account.getIsVip());
return false;
}
return true;
}
}
掘友等级实现类
@Slf4j
public class Level extends MultiLimit {
/**
* 得到配置的限制、我们这边写死了限制的值
* @return 限制值
*/
@Override
public List<String> getLimitValue() {
return Arrays.asList("JY1", "JY2");
}
/**
* 处理用户是否是匹配等级
* @return true 匹配、false不匹配。
*/
@Override
public Boolean execute() {
// 拿到当前用户信息、可以通过第三方或者本地库获取用户会员信息
Account account = AccountContext.getAccount();
// 拿到当前的限制值
List<String> limitValue = getLimitValue();
// 通过第三方或者本地库获取用户会员等级
String level = account.getLevel();
if (!limitValue.contains(level)) {
log.error("校验用户:[{}]是否匹配等级异常、限制的值:{}、用户会员信息:[{}]", account.getId(), limitValue, level);
return false;
}
return true;
}
}
功能测试
明确限制信息、限制是VIP的、掘友等级JY1、或者JY2、明确用户信息不是会员、掘友等级JY1
@Slf4j
public class Demo {
private static List<LimitAdapter<?>> limitAdapter = new ArrayList<>();
static {
limitAdapter.add(new Vip());
limitAdapter.add(new Level());
}
public static void main(String[] args) {
// 用户数据
Account account = new Account();
account.setId(121L);
account.setName("小明");
account.setIsVip(0);
account.setLevel("JY1");
AccountContext.setAccount(account);
LimitAdapter<?> vip = new Vip();
if (vip.isNotMust()) {
log.info("VIP限制为空、不做处理");
} else {
if (vip.execute()) {
log.info("校验VIP通过");
} else {
log.info("校验VIP未通过");
}
}
LimitAdapter<?> level = new Level();
if (level.isNotMust()) {
log.info("等级限制为空、不做处理");
} else {
if (level.execute()) {
log.info("校验等级通过");
} else {
log.info("校验等级未通过");
}
}
}
}
会发现上面代码的实现类是一个一个new的、我们可以把它放在一个集合中、统一遍历处理限制。
@Slf4j
public class Demo {
private static List<LimitAdapter<?>> limitAdapter = new ArrayList<>();
static {
limitAdapter.add(new Vip());
limitAdapter.add(new Level());
}
public static void main(String[] args) {
// 用户数据
Account account = new Account();
account.setId(121L);
account.setName("小明");
account.setIsVip(0);
account.setLevel("JY1");
AccountContext.setAccount(account);
for (LimitAdapter<?> adapter : limitAdapter) {
if (adapter.isNotMust()) {
log.info("限制为空、不做处理");
} else {
if (adapter.execute()) {
log.info("校验通过");
} else {
log.info("校验未通过");
}
}
}
}
}
其实也可以使用Spring容器
将对应的实现类注入到容器中、后续直接通过@Autowired
注入、要注意的就是实现类要加@Component
。
@Autowired
private List<LimitAdapter<?>> limitAdapters;
其实这种不是一个完全把if else去除的、这样做的原因是为了好管理、不会让你的编写的限制条件左一块右一块、减少你对需求的改动一点就离职的心情。(没这样做之前:哪个**
做的、*
到底这个人会不会写代码、写的跟*
一样、**
这还有一块要改、**
那还有一块要改、**
谁爱改谁改、**
不改了、*
、明天离职!)
解决活动限制的值
@Override
public Integer getLimitValue() {
return 1;
}
从上面代码可以看出我们的限制的值是写死了、以及我们上方‘场景简介’介绍的配置化的这个也没有一个很好完善、后需会出另一个版本的代码、做到一个单独的活动限制模块、可以动态的拔插活动限制、以及动态拔插限制选项。