Skip to main content
4 of 9
added 102 characters in body
Amal K
  • 111
  • 1
  • 11

Design pattern for creating and scheduling tests/exams

I have an Exam class that represents an examination/test:

public class Exam
{
    public int Id { get; set; }

    [Required]
    [StringLength(maximumLength: 30, MinimumLength = 1]
    public string Name { get; set; } 

    [Required]
    public Subject Subject { get; init; }  

    [Required]
    public Enrollment Enrollment { get; init; }

    [Required]
    public List<ExamSet> Sets { get; set; } // Sets of questions

    [Required]
    public DateTimeOffset From { get; set; } // Start Time

    [Required]
    public DateTimeOffset To { get; set; }  // End Time

    [Required, Display(Name = "Question Source Repositories")]
    public List<Repository> Repos { get; set; } 

    [Range(0, int.MaxValue)]
    public int SetCount { get; } // Number of questionnaires/question sets to be picked

    public List<int> EasyCounts { get; set; }

    public List<int> MediumCounts { get; set; }

    public List<int> HardCounts { get; set; }

    public List<int> VeryHardCounts { get; set; }

}

Properties of Exam

Type Property Description
Enrollment Enrollment All students part of this enrollment are candidates of this test
DateTimeOffset From Start Time
DateTimeOffset To End Time
List<Repository> Repos The repositories from which questions will be picked
List<int> SetCount The number of ExamSets to be picked
List<int> EasyCounts, MediumCounts, HardCounts, VeryHardCounts Number of easy, medium, hard and very hard questions to be picked for each repository. e.g.: EasyCount[0] means the number of easy questions to be picked for Repos[0].

Each Exam contains multiple ExamSets, each of which contain a different set of questions. One of these sets will be randomly assigned to someone who takes the test. Here is ExamSet:

public class ExamSet
{
    public int Id { get; set; }

    [Required, StringLength(maximumLength: 5, MinimumLength = 1)]
    public string Name { get; set; }

    [Required]
    public Exam Exam { get; set; }

    public IEnumerable<Question> Questions { get; set; }
    
}

As it can be noticed, the Exam class is quite complex. I wonder if using a fluent interface/ the builder pattern is appropriate here. Moreover, the properties Repos, EasyCounts, MediumCounts, HardCounts, VeryHardCounts specify how the questions will be picked and has nothing to do with the test. Can someone suggest a better pattern for this? Question picking will be handled by one of the classes that implement IQuestionPicker(strategy pattern):

public interface IQuestionsPicker
{
    List<Questionnaire> Pick(Repository repo,
                             int setCount,
                             IDictionary<QuestionDifficulty, int> questionCount);
} 

QuestionDifficulty is an enum:

enum QuestionDifficulty
{
    Easy,
    Medium,
    Hard,
    VeryHard
}

I need to write a method that takes in an IQuestionPicker as argument and calls Pick() and converts the List<Questionnaire> to List<ExamSet>. Should I include this method in the Exam class or make a separate class for this?
If something here is unclear, please let me know.

EDIT

Exam here represents an examination event that will be held online in the future. A new Exam instance creation indicates that an examination event is scheduled to occur in the future hence the start and end times. All students part of the enrollment represented by Enrollment are the candidates of the test. Since, the properties Repos, EasyCounts, MediumCounts, HardCounts, VeryHardCounts are just to dictate how the questions will be picked, I am not sure if I need to store these option properties to the database in the first place.

Amal K
  • 111
  • 1
  • 11