在软件开发中,常常会遇到需要根据不同类型执行不同处理逻辑的场景。如果直接使用大量的 if-else
或 switch-case
,代码会变得冗长且难以维护。为了解决这个问题,我们可以采用策略模式和工厂模式,使代码结构更加清晰,且方便扩展。
下面,我将结合代码,详细讲解这种设计思路,并说明实现后数据的流向。特别是,对于工厂类的设计,我们将进行详细的拆分和讲解。
有一个试题需求,需要处理多种类型的题目:
每种题型的处理逻辑不同,如果直接在代码中大量使用条件判断,不利于代码的维护和扩展。
SubjectTypeHandler
public interface SubjectTypeHandler {
/**
* 获取处理器对应的题目类型
*/
SubjectInfoTypeEnum getHandlerType();
/**
* 添加题目的方法
*/
void add(SubjectInfoBO subjectInfoBO);
}
getHandlerType()
:返回处理器对应的题目类型枚举。add(SubjectInfoBO subjectInfoBO)
:处理添加题目的方法。RadioTypeHandler
public class RadioTypeHandler implements SubjectTypeHandler {
@Override
public SubjectInfoTypeEnum getHandlerType() {
return SubjectInfoTypeEnum.RADIO;
}
@Override
public void add(SubjectInfoBO subjectInfoBO) {
// 实现单选题的添加逻辑
System.out.println("添加单选题:" + subjectInfoBO);
}
}
MultipleTypeHandler
public class MultipleTypeHandler implements SubjectTypeHandler {
@Override
public SubjectInfoTypeEnum getHandlerType() {
return SubjectInfoTypeEnum.MULTIPLE;
}
@Override
public void add(SubjectInfoBO subjectInfoBO) {
// 实现多选题的添加逻辑
System.out.println("添加多选题:" + subjectInfoBO);
}
}
JudgeTypeHandler
public class JudgeTypeHandler implements SubjectTypeHandler {
@Override
public SubjectInfoTypeEnum getHandlerType() {
return SubjectInfoTypeEnum.JUDGE;
}
@Override
public void add(SubjectInfoBO subjectInfoBO) {
// 实现判断题的添加逻辑
System.out.println("添加判断题:" + subjectInfoBO);
}
}
BriefTypeHandler
public class BriefTypeHandler implements SubjectTypeHandler {
@Override
public SubjectInfoTypeEnum getHandlerType() {
return SubjectInfoTypeEnum.BRIEF;
}
@Override
public void add(SubjectInfoBO subjectInfoBO) {
// 实现简答题的添加逻辑
System.out.println("添加简答题:" + subjectInfoBO);
}
}
SubjectTypeHandlerFactory
下面,我们对工厂类的设计进行详细的拆分和讲解。
@Component
public class SubjectTypeHandlerFactory implements InitializingBean {
// 注入所有实现了 SubjectTypeHandler 接口的处理器
@Resource
private List<SubjectTypeHandler> subjectTypeHandlerList;
private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();
/**
* 根据题目类型获取对应的处理器
*/
public SubjectTypeHandler getHandler(int subjectType) {
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
return handlerMap.get(typeEnum);
}
@Override
public void afterPropertiesSet() {
// 将处理器按题目类型存入 Map
for (SubjectTypeHandler handler : subjectTypeHandlerList) {
handlerMap.put(handler.getHandlerType(), handler);
}
}
}
一定要注意添加@Component注解,表示将代码交给springboot托管,否则代码不会生效,这样在springboot在启动完成之后,我们的Handler就被装配进了spring容器了。
// 注入所有实现了 SubjectTypeHandler 接口的处理器
@Resource
private List<SubjectTypeHandler> subjectTypeHandlerList;
private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();
subjectTypeHandlerList
:通过 @Resource
注解,Spring 会自动注入容器中所有实现了 SubjectTypeHandler
接口的 Bean。handlerMap
:用于存储题目类型与对应处理器的映射关系。afterPropertiesSet()
@Override
public void afterPropertiesSet() {
// 将处理器按题目类型存入 Map
for (SubjectTypeHandler handler : subjectTypeHandlerList) {
handlerMap.put(handler.getHandlerType(), handler);
}
}
afterPropertiesSet()
方法。逻辑:
subjectTypeHandlerList
,获取每个处理器。getHandlerType()
方法,获取对应的题目类型。handlerMap
,建立映射关系。getHandler(int subjectType)
public SubjectTypeHandler getHandler(int subjectType) {
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
return handlerMap.get(typeEnum);
}
subjectType
,题目类型的整数表示。逻辑:
SubjectInfoTypeEnum.getByCode(subjectType)
,将整数类型转换为对应的枚举类型 SubjectInfoTypeEnum
。handlerMap
中获取对应的处理器。SubjectTypeHandler
,对应题目类型的处理器。@Component
@Component
public class SubjectTypeHandlerFactory implements InitializingBean { ... }
@Component
:将工厂类声明为一个 Spring Bean,交由 Spring 容器管理。implements InitializingBean
:实现 InitializingBean
接口,目的是在 Bean 初始化后执行 afterPropertiesSet()
方法。@Service
public class SubjectService {
@Autowired
private SubjectTypeHandlerFactory handlerFactory;
public void addSubject(SubjectInfoBO subjectInfoBO) {
// 获取对应的处理器
SubjectTypeHandler handler = handlerFactory.getHandler(subjectInfoBO.getType());
if (handler != null) {
// 调用处理器的添加方法
handler.add(subjectInfoBO);
} else {
throw new IllegalArgumentException("未知的题目类型");
}
}
}
@Autowired
将 SubjectTypeHandlerFactory
注入到业务层。添加题目方法:
subjectInfoBO.getType()
获取题目类型。getHandler()
方法获取对应的处理器。add()
方法,处理题目添加逻辑。当需要添加一个新题目时,数据流向如下:
SubjectService.addSubject()
接收 SubjectInfoBO
对象,包含题目的详细信息。SubjectTypeHandlerFactory.getHandler()
根据题目类型返回对应的处理器。add()
方法,执行具体的处理逻辑。SubjectInfoBO subjectInfoBO = new SubjectInfoBO();
subjectInfoBO.setType(1); // 假设 1 代表单选题
subjectInfoBO.setContent("题目内容");
// ... 设置其他属性
subjectService.addSubject(subjectInfoBO);
SubjectInfoBO
,设置题目类型和内容等属性。SubjectService.addSubject()
方法,传入题目对象。public void addSubject(SubjectInfoBO subjectInfoBO) {
// 获取处理器
SubjectTypeHandler handler = handlerFactory.getHandler(subjectInfoBO.getType());
// ...
}
subjectInfoBO
中获取题目类型。getHandler()
方法获取对应的处理器。public SubjectTypeHandler getHandler(int subjectType) {
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
return handlerMap.get(typeEnum);
}
handlerMap
中根据枚举类型获取处理器。if (handler != null) {
handler.add(subjectInfoBO);
} else {
throw new IllegalArgumentException("未知的题目类型");
}
add()
方法。处理器的 add()
方法,例如单选题处理器:
public class RadioTypeHandler implements SubjectTypeHandler {
@Override
public void add(SubjectInfoBO subjectInfoBO) {
// 实现单选题的添加逻辑
System.out.println("添加单选题:" + subjectInfoBO);
// 例如,将题目信息保存到数据库
}
}
用户请求 --> SubjectService.addSubject() --> SubjectTypeHandlerFactory.getHandler() --> 返回对应处理器
|
v
调用处理器的 add() 方法 --> 处理器执行添加逻辑 --> 完成题目添加
SubjectTypeHandlerFactory
的主要职责是根据题目类型返回对应的处理器。这一过程包含:
@Resource
private List<SubjectTypeHandler> subjectTypeHandlerList;
@Resource
注解:由 Spring 自动注入容器中所有实现了 SubjectTypeHandler
接口的 Bean。private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();
handlerMap
:用于存储题目类型和处理器实例的对应关系。SubjectInfoTypeEnum
作为键,确保类型的一致性。@Override
public void afterPropertiesSet() {
for (SubjectTypeHandler handler : subjectTypeHandlerList) {
handlerMap.put(handler.getHandlerType(), handler);
}
}
afterPropertiesSet()
方法:由 InitializingBean
接口提供,在 Bean 的属性设置完成后由 Spring 自动调用。处理逻辑:
subjectTypeHandlerList
中的所有处理器。getHandlerType()
方法,获取其支持的题目类型。handlerMap
。public SubjectTypeHandler getHandler(int subjectType) {
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
return handlerMap.get(typeEnum);
}
subjectType
,题目类型的整数表示。步骤解析:
类型转换:调用 SubjectInfoTypeEnum.getByCode(subjectType)
方法,将整数类型转换为枚举类型。
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
获取处理器:从 handlerMap
中根据枚举类型获取对应的处理器实例。
return handlerMap.get(typeEnum);
null
。在实际应用中,可能需要对获取不到处理器的情况进行处理,可以在 getHandler()
方法中添加异常处理:
public SubjectTypeHandler getHandler(int subjectType) {
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
SubjectTypeHandler handler = handlerMap.get(typeEnum);
if (handler == null) {
throw new IllegalArgumentException("未知的题目类型:" + subjectType);
}
return handler;
}
null
值,将异常抛出,提高代码的健壮性。SubjectTypeHandler
接口,并将其注册到 Spring 容器中,无需修改工厂类的代码。@Component
public class SubjectTypeHandlerFactory implements InitializingBean {
@Resource
private List<SubjectTypeHandler> subjectTypeHandlerList;
private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();
public SubjectTypeHandler getHandler(int subjectType) {
SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
SubjectTypeHandler handler = handlerMap.get(typeEnum);
if (handler == null) {
throw new IllegalArgumentException("未知的题目类型:" + subjectType);
}
return handler;
}
@Override
public void afterPropertiesSet() {
for (SubjectTypeHandler handler : subjectTypeHandlerList) {
handlerMap.put(handler.getHandlerType(), handler);
}
}
}
—— 评论区 ——