用Java实现一个简单的考试系统

用Java实现一个简单的考试系统

需求分析

该考试系统可以实现的功能和系统要求应该包括:

  • 学生:登录、考试、考试后查看成绩
  • 老师:出题目(往题库中添加新题目)、批阅卷子(同时打分)
  • 考试系统:学生的登录校验、存储学生的账号和密码、存储题库、去除题库中重复题目、随机抽取一定数目的题目组合成一张卷子、卷子中题目的选项是随机打乱的

设计思路

首先,最关键的是想好怎么去存储题目,题目由题干、选项以及正确答案3部分组成。
数组、Collection集合,Map集合其实都能实现。

其中,我们很自然想到,使用HashMap去存储可能比较简单,它可以用key-value的形式让题目和答案产生一一对应的关系,题干存储为key,选项和答案存储为value,或者题干和选项存储为key,答案存储为value。其实都行,都可以实现,问题是这样设计真的合理吗?

如果把题目存储为Map集合,看起来也许题目和答案的对应关系很强,但是实际上操作起来可能不是那么方便。map集合的get方法,根据一个键找寻对应的值,这样可读性不是很好,而且map集合的遍历,查找也不是那么方便。

除了变量,数组,集合可以用来存储数据,可不要忘了Java当中还有一个,那就是对象,这才是我们首先要想到的。正所谓万物皆对象,数据封装在对象,可读性也会大大增强。

我们不妨使用一个Question对象,来存储单个的题目。把所有的题目存储到HashSet集合里,理由是HashSet集合可以自动帮我们自动去除重复元素,也就是去除重复的题目。

我们假设只要题干相同,这两个题目就是相同的题目。

为了更方便地操作题目中题干、选项、答案这3部分,我们把这3个内容当作属性来处理。

但是可不要忘了想要让HashSet帮我们去除重复元素,我们得先重写hashCode()方法和equals()方法,也就是告诉HashSet,什么样的两个元素可以认定是重复的。

扫描二维码关注公众号,回复: 10895158 查看本文章

然后,实现学生的登录,系统里需要存储学生的信息,即账号和密码。账号我们存储为String,密码存储为Integer。账号和密码作为键值对可以存储在HashMap里,这样在登录校验的时候不用通过循环来判断账号是否存在以及密码是否正确。

关于类和类之间的关系:学生和系统应该是依赖关系。即学生要考试,考试之前需要先登录。登录以后,才可以进行考试。登录的时候可以把考试系统作为一个对象传入学生的login方法里,使学生和系统建立依赖关系。

老师和系统的关系,也必须是依赖关系,因为老师可以往题库中添加新的题目,而添加题目就要知道往哪个系统的题库中添加。系统中的题库(questionRepository),我们考虑设计为static的,因为它在整个系统中有且仅有一份。

编码实现

Question类:

public class Question {
    private Integer orderNum;//题号
    private String title;//题干
    private String[] option;//选项
    private String answer;//答案

    //不包含题号的构造方法,题号的后期生成卷子的时候赋予的
    public Question(String title, String[] option, String answer) {
        this.title = title;
        this.option = option;
        this.answer = answer;
    }
    @Override
    public boolean equals(Object obj){
        if (this==obj){
            //两对象地址相同,那快别比了,肯定相同的对象
            return true;
        }
        if (obj instanceof Question){
            //首先造型
            Question anotherQue = (Question)obj;
            if(this.title.equals(anotherQue.title)){
                //题目的题干相同,则认为是同一道题,返回true
                return true;
            }
        }
        //obj不是Question类型的,那还比啥呀,肯定不相同
        return false;
    }
    @Override
    public int hashCode(){
        //返回题干字符串的 hashcode
        return this.title.hashCode();
    }

    //get和set······

}

ExamMachine类:

public class ExamMachine {
    private static Map<String,Integer> userBox = new HashMap<>();//用户信息
    private static Set<Question> questionRepository = new HashSet<>();//总的题库

    public ExamMachine(){
        try {
            System.out.println("系统正在启动,请稍等····");
            Thread.sleep(2000);
            System.out.println("正在加载题库····");
            Thread.sleep(2000);
            System.out.println("系统初始化完毕,您可以登录了");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    {
        userBox.put("admin",123);
        userBox.put("java",666);
    }
    {
        questionRepository.add(new Question("假设web应用的文档根目录为MyApp,那么可以从哪里找到database.jar文件",new String[]{"MyApp目录下","MyApp\\images目录下","MyApp\\WEB-INF目录下","MyApp\\WEB-INF\\lib目录下"},"MyApp\\WEB-INF\\lib目录下"));
        questionRepository.add(new Question("从以下哪一个选项中可以获得Servlet的初始化参数",new String[]{"Servlet","ServletContext","ServletConfig","GenericServlet"},"ServletConfig"));
        questionRepository.add(new Question("哪一个对象可以用于获得浏览器发送的请求。",new String[]{"HttpServletRequest","HttpServletResponse","HttpServlet","Http"},"HttpServletRequest"));
        questionRepository.add(new Question("运行jsp需要安装_______Web服务器",new String[]{"Apache","tomcat","都要安装","IIS"},"tomcat"));
        questionRepository.add(new Question("如何取得数据源",new String[]{"通过Http","通过ftp","JNDI","通过Connection对象"},"JNDI"));
        questionRepository.add(new Question("下列哪一个接口定义了用于查找、创建和删除EJB实例",new String[]{"Home","Remote","Local","Message"},"Home"));
        questionRepository.add(new Question("下列哪个为JSP的隐含对象",new String[]{"env","page","jspinfo","context"},"page"));
        questionRepository.add(new Question("下列哪一个是String类下的方法",new String[]{"add","put","compareTo","string"},"compareTo"));
        questionRepository.add(new Question("下列哪一个是java.util包下的类",new String[]{"Math","Object","Enum","Scanner"},"Scanner"));
        questionRepository.add(new Question("下列哪一个不是Java当中的包装类",new String[]{"Integer","Char","Long","Short"},"Char"));
    }
    //学生的登录校验
    public boolean loginCheck(String name,Integer pwd){
        if(this.userBox.get(name)!=null && this.userBox.get(name).equals(pwd)){
            return true;
        }
        else return false;
    }
    //添加题目的方法按理说我们只让老师使用,这里就先不做权限控制了
    public boolean addQuestion(String title,String[] options,String answer){
        Question question = new Question(title,options,answer);
        return this.questionRepository.add(question);
    }
    //生成一张卷子,题目随机
    public ArrayList<Question> generatePaper(){
        int num = 5;
        ArrayList<Question> paper = generatePaper(num);
        return paper;
    }
    //可以指定出几道题目
    public ArrayList<Question> generatePaper(int num){
        System.out.println("系统正在随机抽取题目生成试卷,这可能需要一段时间,请耐心等候···");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ArrayList<Question> questionRepository = new ArrayList<>(this.questionRepository);//把set集合暂时转化为list集合,为的是利用索引来随机
        HashSet<Question> paper = new HashSet<>();//用来存储题目,set集合去重复
        //这个while循环用来生成不重复的一套题目
        while (paper.size()!=num){
            Question question = questionRepository.get(new Random().nextInt(questionRepository.size()));
            paper.add(question);
        }

        ArrayList<Question> newPaper = new ArrayList<>(paper);
        ArrayList<Question> finalPaper = new ArrayList<>();//空的ArrayList,用来存放有打乱顺序的,有带选项号的答案的,没有题号的试题。
        //这个for循环用来给题目中的选项打乱顺序
        for(int i = 0;i<paper.size();i++){
            Question question = newPaper.get(i);
            //选项随机调换顺序,每次生成的选项顺序都不一样
            //生成随机不重复的索引号,用来生成顺序随机的选项
            int[] indexs = this.generateRandomIndexs(4, 4);
            String[] oldOptions = question.getOption();
            String[] newOptions = new String[oldOptions.length];
            char firstOrder = 'A';
            //设置选项的内容,选项的顺序随机
            for (int j = 0;j<oldOptions.length;j++){
                String optionOrder = String.valueOf((char)(firstOrder+j));//将char字符转化为String
                String option = oldOptions[indexs[j]];
                newOptions[j] = optionOrder+"."+option;
                if (option.equals(question.getAnswer())){
                    question.setAnswer(newOptions[j]);
                }
            }
            question.setOption(newOptions);
            finalPaper.add(question);
        }

        return finalPaper;
    }

    //将试卷打印到控制台上,不是自己调用,等着学生的startExam方法里面调用
   public String[] printPaper(ArrayList<Question> paper){
        Scanner input = new Scanner(System.in);
        String[] answers = new String[paper.size()];
        for (int i = 0;i<paper.size();i++){
            Question question = paper.get(i);
            question.setOrderNum(i+1);//设置题号
            System.out.println(question.getOrderNum()+"."+question.getTitle());

            String[] options = question.getOption();
            for (int j = 0;j<options.length;j++){
                System.out.println("\t"+options[j]);
            }
            System.out.println("请输入您认为的正确答案:");
            answers[i] = input.nextLine();//学生的选项
        }
       System.out.println("考试结束,请考生停止作答\n监考老师收取试卷中····");
       try {
           Thread.sleep(3000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       return answers;
   }
   //==============================================================================================
    //生成乱序随机索引号(难),生成随机选项的时候要用它
    private int[] generateRandomIndexs(int num, int bound){
        //num生成几个,bound是边界
        int[] indexs = new int[num];
        for(int i = 0;i<indexs.length;i++){
            indexs[i] = -1;//初始化数组的每个元素为-1
        }
        HashSet<Integer> set = new HashSet<>();//使用Hashset的原因是使用它的不重复规则控制while循环结束的条件
        int i = 0;//数组的索引号
        boolean isUse = false;//标记这个数组是否使用过
        while (set.size()<num){
            if (isUse==false){
                int randomIndex = new Random().nextInt(bound);
                indexs[0] = randomIndex;
                i++;
                set.add(randomIndex);
                isUse = true;
            }else {
                int random = new Random().nextInt(bound);
                boolean isAllNotSame = true;//是否全部不相同
                for (int j = 0;j<i;j++){
                    if (random == indexs[j]){
                        isAllNotSame = false;//只要有一个重复,就置为false,不存
                    }
                }
                if (isAllNotSame){
                    //生成的索引与数组存储的索引不相同,存储它
                    indexs[i] = random;
                    i++;
                    set.add(random);
                }
            }
        }
        return indexs;
    }
}

Student类:

public class Student {
    private String name;
    private Integer password;
    private String examNum;//考号,没有登录系统则为null

    public Student() {
    }

    public Student(String name, Integer password) {
        this.name = name;
        this.password = password;
    }
    //学生登录
    public String login(ExamMachine em){
        boolean checkResult = em.loginCheck(this.name, this.password);
        if (checkResult){
            examNum = UUID.randomUUID().toString().replace("-","");//登录成功,实例化考生考号
            System.out.println("登录成功!\n请考生"+this.getName()+"凭借考号"+examNum+"开始作答.\n不要作弊,一旦发现严肃处理!!!");
        }else {
            System.err.println("登录失败,用户名或密码错误");
        }
        return examNum;
    }
    //学生开始考试
    public String[] startExam(ExamMachine em,ArrayList<Question> paper){
        if (this.examNum.isEmpty()){
            System.err.println("您还没有登录,请您先登录系统!");
            return null;
        }
        String[] answers = em.printPaper(paper);

        return answers;
    }
    //get以及set方法····

}

Teacher类:

public class Teacher {
    //往题库里添加新的题目
    public boolean addQuestion(ExamMachine em,String title,String[] options,String answer){
        Question question = new Question(title,options,answer);
        return em.addQuestion(title,options,answer);
    }
    //批阅卷子,打分数
    public float checkPaper(ArrayList<Question> paper,String[] answer){
        try {
            System.out.println("系统正在提交答案···");
            Thread.sleep(2000);
            System.out.println("老师们正在批阅,请耐心等候····");
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        float oneQueScore = 100F/paper.size();//一道题的分数
        float finalScore = 0;
        for (int i = 0;i<paper.size();i++){
            String trueAnswer = paper.get(i).getAnswer().substring(0,1);//把选项提取出来,charAt也可以
            if(trueAnswer.equalsIgnoreCase(answer[i])){
                finalScore+=oneQueScore;
            }
        }
        return finalScore;
    }
}

测试函数:

public class TestMain {
    public static void main(String[] args) {
        ExamMachine examMachine = new ExamMachine();
        Teacher teacher = new Teacher();
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名");
        String name = input.nextLine();
        System.out.println("请输入密码");
        Integer password = input.nextInt();

        Student student = new Student(name,password);
        student.login(examMachine);

        ArrayList<Question> paper = examMachine.generatePaper(5);
        String[] answers = student.startExam(examMachine, paper);
        float score = teacher.checkPaper(paper, answers);
        System.out.println(student.getName()+"的最终成绩为:"+score+"分,(满分为100分)");
    }
}
发布了68 篇原创文章 · 获赞 57 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43598138/article/details/105578755