zoukankan      html  css  js  c++  java
  • 4.5 出题策略的设计和实现(随机出题)

    在线考试系统提供了根据教师制定的出题策略随机生成试卷的功能。下面看看出题策略部分的详细类图4-15






    图4-15 出题策略模块类图

    可以看出该部分和试卷部分的类图有些相似。这里PaperStrategyPaper类对应。PaperStrategy(出题策略)是用来生成Paper的。StrategyContainer是用来生成QuestionContainer的。而StrategyItem(策略项)是用来生成试题Question的。下面先从整体上介绍出题策略的概念。出题策略就是一个生成试卷的模板。这个模板制定了要出几个大题。每个大题包含了那些小题。出几个大题比较简单想要出几个大题就给一个出题策略PaperStrategy对象创建几个StrategyContainer子对象就可以了。关键是每个大题包含那些小题比较复杂。这里引入策略项的概念(StrategyItem)。每个大题可以有多个策略项。每个策略项有个QuestionContent集合和分值(ScoreValue),出题数(Count)属性。策略项的GetQuesitons方法会从引用的QuestionContent对象中随机挑出Count个,并根据ScoreValue属性生成Count个分值为ScoreValueQuestion对象。每个策略项引用的多个QuestionContent对象代表了老师想出的一个知识点中的备选题。下面代码是PaperStrategy类的 GetPaper 方法。该方法创建一个新的Paper对象并遍历每个StrategyContainer子对象。然后将每个StrategyContainer生成的大题QuestionContainer对象加入到新建的Paper对象中。

    public Paper GetPaper()
    {
          Paper paper 
    = new Paper();
          paper.IsSubmited 
    = false;
          
    foreach (StrategyContainer container in strategyContainers)
          
    {
              QuestionContainer qustionContainer 
    = container.GetQuestionContainer();
               qustionContainer.Paper 
    = paper;
               paper.QuestionContainers.Add(qustionContainer);
                    
           }

            
    return paper;
    }

    下面再看看每个StrategyContainer是如何生成QuestionContainer对象的。下面是StrategyContainer类的GetQuestionContainer方法


     public QuestionContainer GetQuestionContainer()
            
    {
                QuestionContainer result 
    = new QuestionContainer();
                result.Title 
    = title;
                
    foreach (StrategyItem item in strategyItems)
                
    {
                    IList
    <Question> questions = item.GetQuestions();
                    
    foreach (Question q in questions)
                    
    {
                        q.QuestionContainer 
    = result;
                        result.Questions.Add(q);
                    }

                }

                
    return result;
            }

    上面方法创建并返回了一个新的QuestionContainer对象,并遍历自己的StrategyItem子对象。将每个StrategyItem生成的试题Question对象全部加入到新建的QuestionContainer对象。

    最后再来看下StrategyItem是如何随机地从指定的出题范围返回指定数量的Question对象的。下面是StrategyItemGetQuestions方法。

     public IList<Question> GetQuestions()
            
    {
                IList
    <Question> result = new List<Question>();
                IList
    <int> sourceList = new List<int>();
                
    for (int i = 0; i < QuestionContents.Count; i++)
                    sourceList.Add(i);
                IList
    <int> resultList = RandomNumberHelper.RandomSelect(sourceList, count);
                
    foreach (int i in resultList)
                
    {
                    Question question 
    = new Question();
                    question.Content 
    = QuestionContents[i];
                    question.ScoreValue 
    = ScoreValue;
                    result.Add(question);
                }

                
    return result;
            }


    该方法根据RandomNumberHelper.RandomSelect来随机的从StrategyItemQuestionContents集合属性中随机的选择指定数目的QuestionContents集合的一个子集。并根据子集来生成一个Question对象的集合并返回。这样就完成了根据出题策略生成试卷的功能。下面介绍下随机出题的算法。即从QuestionContents集合中随机选取指定数目的QuestionContent对象。该集合的定义如下。

    IList<QuestionContent> QuestionContents = new List<QuestionContent>();

    因为是用List来存储的。所以抽取题目的方法是。随机的选取QuestionContents集合的几个下标。比如QuestionContents5个题目想选两个可以从0~4五个数字中选择两个不同的数字.比如选择了13。然后就可以通过QuestionContents[1]QuestionContents[3]取出要的两个题目。下面给出如何从一个下标的范围中随机选取指定数目下标的算法。

    class RandomNumberHelper
    {
         
    public static IList<int> RandomSelect(IList<int> sourceList, int selectCount)
         
    {
             
    if (selectCount > sourceList.Count)
               
    throw new ArgumentOutOfRangeException("selectCount必需大于sourceList.Count");
             IList
    <int> resultList = new List<int>();
            
    for (int i = 0; i < selectCount; i++)
            
    {
                   
    int nextIndex = GetRandomNumber(1, sourceList.Count);
                   
    int nextNumber = sourceList[nextIndex - 1];
                   sourceList.RemoveAt(nextIndex 
    - 1);
                   resultList.Add(nextNumber);
             }

            
    return resultList;
        }

        
    public static int GetRandomNumber(int minValue, int maxValue)
        
    {
              
    return random.Next(minValue, maxValue + 1);
        }

        
    private static Random random = new Random();
    }

    RandomSelect方法从给定下标集合sourceList中随机的选取selectCount个并将选取结果放到resultList中返回。该算法比网上用递归的方式实现算法效率要高。因为该算法在从sourceList中选出一个下标后就将该下标从sourceList中删除。所以下次在从sourceList中选的时候就不可能再重复挑出已经挑选过的下标。这样就避免了因为随机数不确定性带来的重复筛选的问题。

  • 相关阅读:
    MySQL 中文显示乱码
    sprintf
    持续集成
    两个数据库中的数据同步问题(转)
    指针和引用的区别
    #define,const,typedef三者联系与区别
    [转载]selenium webdriver学习(八)
    PHPUnit学习安装
    CI是什么?
    图形界面的操作(转)
  • 原文地址:https://www.cnblogs.com/xhan/p/1202968.html
Copyright © 2011-2022 走看看