前言
起源是看了一篇文章在 Spring Boot 中,如何干掉 if else!,有兴趣的可以看下。感觉工作中也经常处理类似的问题,就整理了一下。
选秀节目只是当作一个场景,并不会讲太多,如果你真的有兴趣也可以联系我(认真脸。
选手分组
背景
选秀节目事前会让参赛者填一份资料,除了基本信息,还有你的定位,比如主唱、主舞、rap,节目组需要对参赛选手进行一个简单的分组。
实现
定义一个参赛选手类
@Data
public class User {
private Long id;
private String name;
private int age;
private Position position;
}
Position是个枚举
public enum Position {
/**
* 主唱
*/
VOCAL,
/**
* 主舞
*/
DANCE,
/**
* RAP
*/
RAP
}
定义一个分组的接口
public interface IGroupService {
void group(User user);
}
最直接的实现方式就是if else或者switch
@Slf4j
@Service
public class GroupServiceImpl implements IGroupService {
@Override
public void group(User user) {
if (user.getPosition() == Position.VOCAL) {
log.info("{}({})划分到主唱组", user.getName(), user.getId());
}
if (user.getPosition() == Position.DANCE) {
log.info("{}({})划分到主舞组", user.getName(), user.getId());
}
if (user.getPosition() == Position.RAP) {
log.info("{}({})划分到RAP组", user.getName(), user.getId());
}
}
}
优化
可以定义一个handler
public interface IGroupHandler {
void group(User user);
/**
* 能处理的定位
*
* @return
*/
Position getPosition();
}
再写三个实现
@Slf4j
@Component
public class VocalGroupHandler implements IGroupHandler {
@Override
public void group(User user) {
log.info("{}({})划分到主唱组", user.getName(), user.getId());
}
@Override
public Position getPosition() {
return Position.VOCAL;
}
}
@Slf4j
@Component
public class DanceGroupHandler implements IGroupHandler {
@Override
public void group(User user) {
log.info("{}({})划分到主舞组", user.getName(), user.getId());
}
@Override
public Position getPosition() {
return Position.DANCE;
}
}
@Slf4j
@Component
public class RapGroupHandler implements IGroupHandler {
@Override
public void group(User user) {
log.info("{}({})划分到RAP组", user.getName(), user.getId());
}
@Override
public Position getPosition() {
return Position.RAP;
}
}
然后在服务类里注入这些handler,在处理的时候通过每个handler能处理的类型,找到具体的handler
@Service
public class GroupServiceV2Impl implements IGroupService {
public Map<Position, IGroupHandler> handlerMap;
public GroupServiceV2Impl(List<IGroupHandler> groupHandlers) {
handlerMap = groupHandlers.stream().collect(Collectors.toMap(IGroupHandler::getPosition, Function.identity()));
}
@Override
public void group(User user) {
IGroupHandler groupHandler = handlerMap.get(user.getPosition());
if (groupHandler == null) {
throw new IllegalArgumentException("无法处理的position:" + user.getPosition());
}
groupHandler.group(user);
}
}
这里利用了spring的依赖注入,通过构造器注入把所有的handler进行注入。
后续如果Position有变更,只需要新增或修改相应的handler类即可。
选手评级
背景
选秀节目最开始会对选手评级,A、B、C、D、E、F几个等级。
导师们也都有各自擅长的领域,比如评价分为几个方面,唱跳rap,没有篮球。
可以假定一个评价规则
等级 | 评价规则 |
---|---|
A | 3项都超过90分 |
B | 2项都超过90分 |
C | 1项超过90分 |
D | 平均分80以上 |
E | 平均分75以上 |
F | 不符合以上的都是F |
分析
跟刚才的有些类似,但不同点是之前的条件是互斥的,但这里的条件并不是,满足高等级的很可能满足低等级,比如A等级的满足其他的所有条件,所有人也都可以划分为F等级。
所以这里处理是有顺序的,不满足高等级才会分到低等级。
实现
定义评级
public enum Rate {
A, B, C, D, E, F
}
定义对选手的评价
@Data
public class Score {
private Long uid;
private int vocal;
private int dance;
private int rap;
}
定义获取评级的接口
public interface IRateService {
Rate getRate(Score score);
}
按照刚才的思路,我们也可以定义每个级别handler
public interface IRateHandler {
Rate getRate();
/**
* 条件是否满足
*
* @return
*/
boolean isMatch(Score score);
}
实现就不都写了,要注意的是F等级应该是默认是true
@Component
public class RateAHandler implements IRateHandler {
@Override
public Rate getRate() {
return Rate.A;
}
@Override
public boolean isMatch(Score score) {
return score.getVocal() > 90 && score.getDance() > 90 && score.getRap() > 90;
}
}
@Component
public class RateFHandler implements IRateHandler {
@Override
public Rate getRate() {
return Rate.F;
}
@Override
public boolean isMatch(Score score) {
return true;
}
}
服务的实现与刚才类似,但是由于现在的条件不是那么单一的判断,无法使用map
@Service
public class RateServiceImpl implements IRateService {
public List<IRateHandler> rateHandlers;
public RateServiceImpl(List<IRateHandler> rateHandlers) {
this.rateHandlers = rateHandlers;
}
@Override
public Rate getRate(Score score) {
for (IRateHandler rateHandler : rateHandlers) {
if (rateHandler.isMatch(score)) {
return rateHandler.getRate();
}
}
throw new IllegalArgumentException("无法处理");
}
}
这里还有个问题,就是handler应该是有顺序的,有两种实现思路
- 在handler上加
@Order
注解,在注入的时候就已经排好序了 - 在
IRateHandler
上定义一个获取优先级的方法,然后在RateServiceImpl
的构造函数里,根据优先级进行排序。
然后就搞定了。
后记
这种实现方式的使用场景还是很多的,应对更复杂的场景还可以提供一些公共的抽象类,减少一些重复的代码。
如果你有更好的实现方式也欢迎留言。
看到了这里一定是真爱了,关注微信公众号【憨憨的春天】第一时间获取更新
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。