如何用策略模式消除满屏的if-else
前言
最近在迁接口的过程中遇到一个直播列表页关注Tab的接口,需要根据不同的直播状态对关注的主播进行展示,老接口把所有的直播状态都写到一起了,首先判断该主播的直播状态(直播中/预告中/未开播等),然后执行不同的处理逻辑。
if (input.getType() == 0) {
// 直播中主播的处理逻辑
}else if (input.getType() == 1) {
// 预告中主播的处理逻辑
}else if (input.getType() == 2) {
// 未开播主播的处理逻辑
}
每种逻辑返回的字段很多导致方法很大,阅读起来体验极差,而且以后有什么活动在直播列表页展示也不方面修改。现在考虑使用策略模式来消除这些if-else
。
实现
对于client
,我们要在其中增加一个策略处理器Map<Integer, Processor>
,然后在client
进行bean初始化的时候将所有策略都加载到这个ConcurrentHashMap
中,这样只需向client
传递一个type
参数就可以从该map
中找到对应的处理策略的实现类。
1.客户端client
实现InitializingBean
接口会在这个bean初始化后执行afterPropertiesSet
方法在里面将从ApplicationContextHelper
里面获取到的bean都放到map里面去,map的key为策略实现类的业务taype,值为该对象。
/**
* @author zhongye
* @since 2021.08.06
*/
@Component
@Slf4j
public class MyFollowActorsActionletLogic implements InitializingBean {
private final Map<Integer, MyFollowActorsActionletProcessor> typeAndStatementHandle = new ConcurrentHashMap<>();
@Resource
private ApplicationContextHelper applicationContextHelper;
@Override
public void afterPropertiesSet() {
Map<String, MyFollowActorsActionletProcessor> statementHandles =
applicationContextHelper.getBeansOfType(MyFollowActorsActionletProcessor.class);
for (Map.Entry<String, MyFollowActorsActionletProcessor> statementHandle : statementHandles.entrySet()) {
typeAndStatementHandle.put(statementHandle.getValue().getType(), statementHandle.getValue());
}
}
public MyFollowActorsActionletOutput assembleOutput(MyFollowActorsActionletInput input) {
MyFollowActorsActionletOutput output = typeAndStatementHandle.get(input.getType()).process(input);
// 处理acm,加上tId
dealFollowListAcm(output.getData());
// 构造结果
output.setEnd(input.getTotal() < input.getPageSize());
output.setPageIndex(output.isEnd() ? input.getPageIndex() : input.getPageIndex() + 1);
return output;
}
}
2.ApplicationContextHelper
是一个实现了ApplicationContextAware
接口的工具类
实现这个接口会在spring容器初始化完成之后调用setApplicationContext
方法,将ApplicationContext
放进去,从而可以拿到spring的容器ApplicationContext
,进而使用这个容器获取我们想要的bean 。
/**
* @author zhongye
* @since 2021.08.06
*/
@Component
public class ApplicationContextHelper implements ApplicationContextAware {
ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
public <T> Map<String, T> getBeansOfType(Class<T> clazz) {
return applicationContext.getBeansOfType(clazz);
}
}
3.策略的抽象类
/**
* MyFollowActorsActionlet 的处理策略接口
* 0:直播中 1:预告中 2: 未开播
*
* @author zhongye
* @since 2021.08.06
*/
public interface MyFollowActorsActionletProcessor {
/**
* 这个类型,决定了使用哪个具体的实现类
*
* @return 消息类型
*/
int getType();
/**
* 处理逻辑
*
* @param input 入参
* @return MyFollowActorsActionletOutput
*/
MyFollowActorsActionletOutput process(MyFollowActorsActionletInput input);
}
4.策略的实现类
/**
* 直播列表页关注TAB-正在直播中主播处理逻辑处
*
* @author zhongye
* @since 2021.08.06
*/
@Component
@Slf4j
public class MyFollowLivingActorProcessor implements MyFollowActorsActionletProcessor {
@Override
public int getType() {
//🤔 type多的时候可以写成枚举类
return 0;
}
@Override
public MyFollowActorsActionletOutput process(MyFollowActorsActionletInput input) {
MyFollowActorsActionletOutput output = new MyFollowActorsActionletOutput();
output.setData(Lists.newArrayList());
long userId = input.getLoginUserId();
// 查询直播间信息
List<FollowActorsRoomDTO> roomInfos = actorFollowComponent.buildRoomList(userId, input.getPageIndex(), input.getPageSize());
List<Long> actorIds = roomInfos.stream().map(FollowActorsRoomDTO::getActorId).collect(Collectors.toList());
// 查询主播列表
Map<Long, UsersInfo> usersInfoMap = userInfoRemoteService.mapByUserIds(actorIds);
// 查询陪伴天数
Map<Long, Integer> daysMap = myFollowActorsActionletLogic.getAccompanyDaysByUser(userId, actorIds);
// 构造数据
for (FollowActorsRoomDTO roomInfo : roomInfos) {
UsersInfo usersInfo = usersInfoMap.get(roomInfo.getActorId());
if (usersInfo == null) {
continue;
}
FollowActorsDataItemDTO dataItem = myFollowActorsActionletLogic.buildDataItem(
daysMap.getOrDefault(usersInfo.getUserId(), 0), input.getType(), usersInfo);
dataItem.setRoomInfo(roomInfo);
output.getData().add(dataItem);
}
input.setTotal(roomInfos.size());
return output;
}
}
既已览卷至此,何不品评一二: