工厂模式与策略模式结合的最佳实践
1. 目录结构
(此处省略目录结构图)
2. SubjectType.java 策略枚举类
package com.sunxiansheng.design_pattern.factory_strategy.strategyenum;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Description: 题目类型,分为单选、多选、判断、简答
*/
public enum SubjectType {
// 单选题
SINGLE_CHOICE(1, "单选题"),
// 多选题
MULTIPLE_CHOICE(2, "多选题"),
// 判断题
JUDGMENT(3, "判断题"),
// 简答题
SHORT_ANSWER(4, "简答题");
private int code;
private String desc;
SubjectType(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
// 将枚举转为 map
public static Map<Integer, SubjectType> enumeratedMaps = Stream.of(SubjectType.values())
.collect(Collectors.toMap(SubjectType::getCode, Function.identity()));
/**
* 根据 code 获取题目类型
*
* @param code
* @return
*/
public static SubjectType getSubjectType(int code) {
return enumeratedMaps.get(code);
}
}
3. ISubjectStrategy.java 策略接口
package com.sunxiansheng.design_pattern.factory_strategy.strategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
/**
* Description: 题目策略
*/
public interface ISubjectStrategy {
/**
* 获取题目类型
*
* @return
*/
SubjectType getSubjectType();
/**
* 处理题目
*/
void handleQuestion();
}
4. 策略接口实现类
1. Judgment.java
package com.sunxiansheng.design_pattern.factory_strategy.strategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
/**
* Description: 判断题策略
*/
public class Judgment implements ISubjectStrategy {
@Override
public void handleQuestion() {
System.out.println("处理判断题");
}
@Override
public SubjectType getSubjectType() {
return SubjectType.JUDGMENT;
}
}
2. MultipleChoice.java
package com.sunxiansheng.design_pattern.factory_strategy.strategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
/**
* Description: 多选题策略
*/
public class MultipleChoice implements ISubjectStrategy {
@Override
public void handleQuestion() {
System.out.println("处理多选题");
}
@Override
public SubjectType getSubjectType() {
return SubjectType.MULTIPLE_CHOICE;
}
}
3. ShortAnswer.java
package com.sunxiansheng.design_pattern.factory_strategy.strategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
/**
* Description: 简答题策略
*/
public class ShortAnswer implements ISubjectStrategy {
@Override
public void handleQuestion() {
System.out.println("处理简答题");
}
@Override
public SubjectType getSubjectType() {
return SubjectType.SHORT_ANSWER;
}
}
4. SingleChoice.java
package com.sunxiansheng.design_pattern.factory_strategy.strategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
/**
* Description: 单选题策略
*/
public class SingleChoice implements ISubjectStrategy {
@Override
public void handleQuestion() {
System.out.println("处理单选题");
}
@Override
public SubjectType getSubjectType() {
return SubjectType.SINGLE_CHOICE;
}
}
5. Strategy.java 策略工厂
package com.sunxiansheng.design_pattern.factory_strategy.factory;
import com.sunxiansheng.design_pattern.factory_strategy.strategy.ISubjectStrategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Description: 策略工厂
*/
public class Strategy {
/**
* 正常情况下是使用 Spring 的依赖注入,这里直接使用反射模拟了
*/
private List<ISubjectStrategy> strategies = new ArrayList<>();
/**
* 策略 map,将 list 转为 map,方便根据题目类型获取策略
*/
private Map<SubjectType, ISubjectStrategy> strategyMap = new HashMap<>();
{
// 反射模拟 Spring 的依赖注入
try {
Class<?> singleChoice = Class.forName("com.sunxiansheng.design_pattern.factory_strategy.strategy.SingleChoice");
Class<?> multipleChoice = Class.forName("com.sunxiansheng.design_pattern.factory_strategy.strategy.MultipleChoice");
Class<?> judgment = Class.forName("com.sunxiansheng.design_pattern.factory_strategy.strategy.Judgment");
Class<?> shortAnswer = Class.forName("com.sunxiansheng.design_pattern.factory_strategy.strategy.ShortAnswer");
strategies.add((ISubjectStrategy) singleChoice.newInstance());
strategies.add((ISubjectStrategy) multipleChoice.newInstance());
strategies.add((ISubjectStrategy) judgment.newInstance());
strategies.add((ISubjectStrategy) shortAnswer.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
{
// 将 list 转为 map
strategies.forEach(strategy -> strategyMap.put(strategy.getSubjectType(), strategy));
}
/**
* 根据题目类型获取策略
*
* @param subjectType
* @return
*/
public ISubjectStrategy getStrategy(SubjectType subjectType) {
return strategyMap.get(subjectType);
}
}
6. Client.java 客户端
package com.sunxiansheng.design_pattern.factory_strategy;
import com.sunxiansheng.design_pattern.factory_strategy.factory.Strategy;
import com.sunxiansheng.design_pattern.factory_strategy.strategyenum.SubjectType;
/**
* Description: 客户端
*/
public class Client {
public static void main(String[] args) {
// 策略工厂
Strategy strategy = new Strategy();
// 四种策略
strategy.getStrategy(SubjectType.SINGLE_CHOICE).handleQuestion();
strategy.getStrategy(SubjectType.MULTIPLE_CHOICE).handleQuestion();
strategy.getStrategy(SubjectType.JUDGMENT).handleQuestion();
strategy.getStrategy(SubjectType.SHORT_ANSWER).handleQuestion();
}
}
7. 小结
工厂模式与策略模式结合首先需要定义策略的枚举类,设置不同题目类型的枚举值。接着定义一个策略接口,包含获取题目类型和处理题目的方法,各具体策略类实现该接口。随后实现一个策略工厂,通常使用 Spring 的依赖注入,本例中为了演示使用反射模拟初始化过程。在 Bean 初始化阶段,将策略列表转换为 Map,最后提供根据题目类型枚举获取对应策略的方法,从而实现业务逻辑的动态分发与解耦。


