业务背景
培训系统中的考试领域,在考生开始考试时,会根据当前试卷的状态来执行不同的业务处理。这其实是一个典型的工厂模式样例。
优化前
使用大量的if else来区分不同状态的业务。
if (status = 可以考试){
执行答卷初始化;
生成防止答卷超时未提交的定时任务;
}else if (status = 已有答卷在考试中){
返回前台已经开始的答卷内容;
}else if (status = 未完成学习任务){
返回前台继续完成学习任务的提示;
}
优化后
定义一个考卷对象
ExamAnswerDTO,用于返回给前台具体的考卷内容,具体属性就不展示了。
定义考卷状态的枚举
msg定义了当前状态的详情,在一些状态下也可用于对前台展示的提示。
beanName是每一个状态所对应的执行业务的beanName,这个设计模式能正确执行的关键点。
ExamAnswerStatus
START_EXAM(0,"开始考试","startExamBean"),
EXIST_EXAM(1,"已有答卷在考试中","existExamBean"),
NO_FINISH(2,"还有未完成的学习任务","noFinishBean");
private final Integer code;
private final String msg;
private final String beanName;
创建工厂和实现
// 工厂
public interface ExamAnswerInterface {
// ExamAnswerDTO 中为考卷内容
Result<ExamAnswerDTO> examAnswer(ExamAnswerReq req);
}
// 开始考试的实现
@Service
public StartExamBean implements ExamAnswerInterface{
@Override
public Result<ExamAnswerDTO> examAnswer(ExamAnswerReq req){
// 初始化答卷,并将答卷内容返回
// 生成防止答卷超时未提交的定时任务
}
}
// 已有答卷在考试中
@Service
public ExistExamBean implements ExamAnswerInterface{
@Override
public Result<ExamAnswerDTO> examAnswer(ExamAnswerReq req){
// 查询已有答卷内容,并返回
}
}
// 还有未完成的学习任务
@Service
public NoFinishBean implements ExamAnswerInterface{
@Override
public Result<ExamAnswerDTO> examAnswer(ExamAnswerReq req){
return Result.createFaild("还有未完成的学习任务");
}
}
开始考试
public Result<ExamAnswerDTO> examAnswer(Request request){
try{
// 分布式锁防止重复考试
commmentLock.tryLock("startExamLock" + examId);
ExamAnswerStatus status = 另外的方法计算是否可以开始考试;
// 从容器中获取bean
ExamAnswerInterface examAnswerInterface = applicationContextComponent
.getApplicationContext()
.getBean(judgeExamResult.getBeanName(), ExamResultInterface.class);
Result<ExamAnswerDTO> examAnswer = examAnswerInterface.examAnswer();
// 做返回处理
}catch (Exception e){
// 处理异常
}finally {
commmentLock.unlock();
}
}
获取bean
因为各自的工厂实现中还会用到其它的bean(例如查询等动作),所以这里的实现类如果能使用spring容器中的bean,就可以用自动注入的方式来管理用到的其它bean,会方便很多。
可以借助ApplicationContextAware,来实现获取bean,在spring容器初始化的时候,就会执行setApplicationContext保存上下文。
@Component
public class ApplicationContextComponent implements ApplicationContextAware {
private static ApplicationContext context;
public ApplicationContext getApplicationContext() {
return context;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}