You’re writing an application that manages online courses. A course is completed in many different ways. A user must do one or more of the follow to complete the course:
- spend x amount of hours in the course
- take a test, and pass the test (a passing score could be different for every course)
- take all the lessons in a course
- some other requirements you don’t know about yet
When a course is completed, some event needs to happen. The event depends on the course. One or more of the following may need to happen:
- A custom certificate is created for the user
- An organization is alerted via email, HTTP callback, or something else
- some other requirements you don’t know about yet
Many of the courses are almost identical with respect to their requirements, but some are completely unique. There are a lot of courses, upwards of 50, and more are always being added.
How would you design an application like this? Is there a design pattern you can use to eliminate redundant code, and make it easy to add/edit courses?
Here how I would start sketching it out…
You have a Course object which accepts a Requirements object and a OnCompleteActions object in its constructor… granted I would make the constructor internal and Create a CourseBuilder that will know how to build all of the different courses but…
When ever the Course is updated it checks if the Requirements are met by passing itself to the Requirements object. If it meets the requirements it then passes itself to the OnCompleteActions.
Requiremetns object is nothing but an aggregate list of IRequirement which you could fine tune based on the Course that you create… the AreMetBy method simple enumerates all of your IRequirements in the list and checks to see if your course satisfies them all…
Then you could have all sorts of different Requirements that implement IRequirement…
Same idea for the OnCompleteActions would have a list of one or More IOnCompleteAction that would execute each one. ex. CreateCertificateOnCompleteAction, SendEmailOnCompleteAction, etc.
By encapsulating each possible Requirement in its own class you can then Build a course that would have a MinimumHourRequirement, a PassedAllTestRequirement, etc. You could easily add new requirements as you go because they are all implementing the same interface. You probably have to add some limit properties as you go (like minimumHours) but the real work is done inside of the IsMetBy() method…
Good luck!