何为工厂模式
工厂模式是一种创建型模式,工厂只对外暴露创建对象的接口,由外部调用者决定该创建哪个对象。这隐藏了每个功能类具体的实现逻辑,让外部可以更简单的调用。
举个例子:我想要买车,我到4s店和销售说我想要啥啥啥款车,销售就会带着你去看,如果money到位,就安排安排手续,这辆车就是你的了。在这个过程中,4s店就是工厂,而产品就是汽车,你不用去了解汽车是怎么组装的,你只需要报一个型号,4s店就会给你提供你需要的车。
在工厂模式中,每种服务更像是商品一样,摆放在工厂类中,供大家挑选,调用者只需要选取它,工厂就会在内部帮你创建一个该服务的实例,然后你就可以愉快地使用它了。
实战案例
假如我现在要开发一个题库,题库中有选择题、判断题、填空题等,每种题目类型我们需要单独的一套操作接口。
常规做法是在业务代码里加狂加if,判断传入的题目是何种类型的,然后根据类型创建相应的对象,之后就是对题目的CRUD操作。
且不谈业务代码太复杂,耦合性高的问题,就是太多if-else既不美观,维护起来也是相当的难受的。
因此我们可以利用工厂模式改造这处代码。
代码实现
目录结构

Enums
题目种类的枚举,没什么好说的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
public enum SubjectInfoTypeEnums { RADIO(1,"单选"), MULTIPLE(2,"多选"), JUDGE(3,"判断"), BRIEF(4,"简答") ;
public int code; public String desc;
SubjectInfoTypeEnums(int code, String desc){ this.code = code; this.desc = desc; }
public static SubjectInfoTypeEnums getEnumByCode(int code){ for(SubjectInfoTypeEnums e : SubjectInfoTypeEnums.values()){ if(e.code == code){ return e; } } return null; } }
|
SubjectHandler
SubjectTypeHandler:
1 2 3 4 5 6 7 8 9 10 11 12
| public interface SubjectTypeHandler {
SubjectInfoTypeEnums getHandlerType();
void add(SubjectInfoBO subjectInfoBO);
}
|
统一入参出参(每次定义类似于这样的接口时,我才能体会到:接口其实是对类行为的约束这句话,下一句是:继承是对类功能的扩展)
BriefTypeHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| * * 单选题 */ public class BriefTypeHandler implements SubjectTypeHandler{ @Override public SubjectInfoTypeEnums getHandlerType() {
return SubjectInfoTypeEnums.BRIEF; }
@Override public void add(SubjectInfoBO subjectInfoBO) { System.out.println("单选题加入:" + subjectInfoBO.getSubjectName()); } }
|
单选题,实现SubjectTypeHandler
JudgeTypeHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| * * 判断题 */ public class JudgeTypeHandler implements SubjectTypeHandler{ @Override public SubjectInfoTypeEnums getHandlerType() { return SubjectInfoTypeEnums.JUDGE; }
@Override public void add(SubjectInfoBO subjectInfoBO) { System.out.println("判断题加入:" + subjectInfoBO.getSubjectName()); } }
|
判断题同样实现SubjectTypeHandler
SubjectFactory

在这个工厂类中,我利用了hashmap存储当前工厂中的产品类
1 2 3 4
|
private Map<SubjectInfoTypeEnums, SubjectTypeHandler> handlerMap = new HashMap<>();
|
init()方法,用来初始化工厂中的map,可以理解为将商品放在柜台上
1 2 3 4 5 6 7 8 9 10 11
| public void init(){ if(handlerMap.isEmpty()){
BriefTypeHandler briefTypeHandler = new BriefTypeHandler(); JudgeTypeHandler judgeTypeHandler = new JudgeTypeHandler(); this.handlerMap.put(briefTypeHandler.getHandlerType(),briefTypeHandler); this.handlerMap.put(judgeTypeHandler.getHandlerType(),judgeTypeHandler); } }
|
getHandler能通过调用者传入的枚举类code,在map中找到对应的handler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public SubjectTypeHandler getHandler(int subjectValue){ try{ SubjectInfoTypeEnums enumByCode = SubjectInfoTypeEnums.getEnumByCode(subjectValue); if(enumByCode == null) { System.out.println("题目类型有误"); return null; } return handlerMap.get(enumByCode); }catch(Exception ex){ System.out.println("未知错误"); return null; } }
|
Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class FactoryMain { public static void main(String[] args) {
SubjectTypeHandlerFactory subjectTypeHandlerFactory = new SubjectTypeHandlerFactory(); subjectTypeHandlerFactory.init();
SubjectInfoBO subjectInfoBO = new SubjectInfoBO(); subjectInfoBO.setId(1L); subjectInfoBO.setSubjectName("我是判断题!"); subjectInfoBO.setSubjectType(3);
SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfoBO.getSubjectType()); handler.add(subjectInfoBO);
} }
|
总结
- 调用者只需要知道你想要调用的handler的映射,可以是名称,也可以是枚举,然后就能通过工厂获得对象,简化了创建对象的过程
- 提高了系统扩展性,如果要添加一种新的产品类,比如加入一中心的题型,只需要在枚举中加入相关code,然后实现接口就可以了,在spring下会自动装配到接口的实现列表里,很容易取到然后初始化工厂map