重学 Java 设计模式:实战原型模式「上机考试多套试,每人题目和答案乱序排列场景」
一、前言
老板你加钱我的代码能飞
程序员这份工作里有两种人;一类是热爱喜欢的、一类是仅当成工作的。而喜欢代码编程的这部分人会极其主动学习去丰富自己的羽翼,也非常喜欢对技术探索力求将学到的知识赋能到平时的业务需求开发中。对于这部分小伙伴来说上班写代码还能赚钱真的是幸福!
怎么成为喜欢编码都那部分人
无论做哪行那业你都喜欢,往往来自从中持续不断都获取成就感。就开发编程而言因为你的一行代码影响到了千千万万的人、因为你的一行代码整个系统更加稳定、因为你的一行代码扛过了所有秒杀等等,这样一行行的代码都是你日积月累学习到的经验。那如果你也想成为这样有成就感的程序员就需要不断的学习,不断的用更多的技能知识把自己编写的代码运用到更核心的系统。
方向不对努力白费
平常你也付出了很多的时间,但就是没有得到多少收益。就像有时候很多小伙伴问我,我是该怎么学一个我没接触过的内容。我的个人经验非常建议,先不要学太多理论性的内容,而是尝试实际操作下,把要学的内容做一些Demo案例出来。这有点像你买了个自行车是先拆了学学怎么个原理,还是先骑几圈呢?哪怕摔了跟头,但那都是必须经历后留下的经验。
同样我也知道很多人看了设计模式收获不大,这主要新人对没有案例或者案例不贴近实际场景没有学习方向导致。太空、太虚、太玄,让人没有抓手!
所以我开始编写以实际案例为着手的方式,讲解设计模式的文章,帮助大家成长的同时也让我自己有所沉淀!
二、开发环境
- JDK 1.8
- Idea + Maven
- 涉及工程三个,可以通过关注公众号:
bugstack虫洞栈
,回复源码下载
获取(打开获取的链接,找到序号18)
工程 | 描述 |
---|---|
itstack-demo-design-4-00 | 场景模拟工程,模拟在线考试题库抽提打乱顺序 |
itstack-demo-design-4-01 | 使用一坨代码实现业务需求,也是对ifelse的使用 |
itstack-demo-design-4-02 | 通过设计模式优化改造代码,产生对比性从而学习 |
三、原型模式介绍
原型模式主要解决的问题就是创建重复对象,而这部分对象
内容本身比较复杂,生成过程可能从库或者RPC接口中获取数据的耗时较长,因此采用克隆的方式节省时间。
其实这种场景经常出现在我们的身边,只不过很少用到自己的开发中,就像;
- 你经常
Ctrl+C
、Ctrl+V
,复制粘贴代码。 - Java多数类中提供的API方法;
Object clone()
。 - 细胞的有丝分裂。
类似以上的场景并不少,但如果让你去思考平时的代码开发中,有用到这样的设计模式吗?确实不那么容易找到,甚至有时候是忽略了这个设计模式的方式。在没有阅读下文之前,也可以思考下哪些场景可以用到。
四、案例场景模拟
每个人都经历过考试,从纸制版到上机答题,大大小小也有几百场。而以前坐在教室里答题身边的人都是一套试卷,考试的时候还能偷摸或者别人给发信息抄一抄答案。
但从一部分可以上机考试的内容开始,在保证大家的公平性一样的题目下,开始出现试题混排更有做的好的答案选项也混排。这样大大的增加了抄的成本,也更好的做到了考试的公平性。
但如果这个公平性的考试需求交给你来完成,你会怎么做?
因为需要实现一个上机考试抽题的服务,因此在这里建造一个题库题目的场景类信息,用于创建;选择题
、问答题
。
1. 场景模拟工程
itstack-demo-design-4-00
└── src
└── main
└── java
└── org.itstack.demo.design
├── AnswerQuestion.java
└── ChoiceQuestion.java
- 在这里模拟了两个试卷题目的类;
ChoiceQuestion
(选择题)、AnswerQuestion
(问答题)。如果是实际的业务场景开发中,会有更多的题目类型,可以回忆一下你的高考试卷。
2. 场景简述
2.1 选择题
public class ChoiceQuestion {
private String name; // 题目
private Map<String, String> option; // 选项;A、B、C、D
private String key; // 答案;B
public ChoiceQuestion() {
}
public ChoiceQuestion(String name, Map<String, String> option, String key) {
this.name = name;
this.option = option;
this.key = key;
}
// ...get/set
}
2.2 问答题
public class AnswerQuestion {
private String name; // 问题
private String key; // 答案
public AnswerQuestion() {
}
public AnswerQuestion(String name, String key) {
this.name = name;
this.key = key;
}
// ...get/set
}
- 以上两个类就是我们场景中需要的物料内容,相对来说比较简单。如果你在测试的时候想扩充学习,可以继续添加一些其他物料(题目类型)。
五、用一坨坨代码实现
今天的实现方式没有ifelse了,但是没有一个类解决不了的业务,只要你胆大!
在以下的例子中我们会按照每一个用户创建试卷的题目,并返回给调用方。
1. 工程结构
itstack-demo-design-4-01
└── src
└── main
└── java
└── org.itstack.demo.design
└── QuestionBankController.java
- 一个类几千行的代码你是否见过,嚯?那今天就再让你见识一下有这样潜质的类!
2. 一把梭实现需求
public class QuestionBankController {
public String createPaper(String candidate, String number) {
List<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>();
List<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>();
Map<String, String> map01 = new HashMap<String, String>();
map01.put("A", "JAVA2 EE");
map01.put("B", "JAVA2 Card");
map01.put("C", "JAVA2 ME");
map01.put("D", "JAVA2 HE");
map01.put("E", "JAVA2 SE");
Map<String, String> map02 = new HashMap<String, String>();
map02.put("A", "JAVA程序的main方法必须写在类里面");
map02.put("B", "JAVA程序中可以有多个main方法");
map02.put("C", "JAVA程序中类名必须与文件名一样");
map02.put("D", "JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来");
Map<String, String> map03 = new HashMap<String, String>();
map03.put("A", "变量由字母、下划线、数字、$符号随意组成;");
map03.put("B", "变量不能以数字作为开头;");
map03.put("C", "A和a在java中是同一个变量;");
map03.put("D", "不同类型的变量,可以起相同的名字;");
Map<String, String> map04 = new HashMap<String, String>();
map04.put("A", "STRING");
map04.put("B", "x3x;");
map04.put("C", "void");
map04.put("D", "de$f");
Map<String, String> map05 = new HashMap<String, String>();
map05.put("A", "31");
map05.put("B", "0");
map05.put("C", "1");
map05.put("D", "2");
choiceQuestionList.add(new ChoiceQuestion("JAVA所定义的版本中不包括", map01, "D"));
choiceQuestionList.add(new ChoiceQuestion("下列说法正确的是", map02, "A"));
choiceQuestionLis