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 |
|---|---|---|
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.