C# Interfaces – Extending Behavior

Architecting Behavior for Extensibility

When designing class behavior, it’s important to remember in the implementation of those objects, future changes are certain, necessitating flexibility to evolving requirements.

Extensibility in Design

When designing behavior in classes, you can simply define functions to be used as object methods, but that assumes the details of each function need not evolve over time.
Instead, you may create a contract of behavior which is then bound to (implemented by) classes, which then may be used to leverage that behavior.

For example, an application needs to report on a class’s schedule related to students.
Each course must report its name, whether or not enrollment enrollment has been completed, and the ability to complete the function of enrollment.

This interface provides a contract which may be implemented by any type of course class.
In this scenario, we’ll have many online classes.
Therefore by implementing this contract, the requirements of the application may be protected and guaranteed to satisfy user needs.

As you can see, the class implements the contract and provides the details of how to enroll a student as well as reporting.

However, not all classes are online. How does the application solve the the requirement to provide in-person classes?

Since a contract/interface for all courses has already been defined, a new interface only need implement the previous interface, then add any new details which are required by all courses of this type, namely the ability to account for limited seating.

Now, when a class, or blueprint for objects of this type is used, the objects not only leverage the interface shared by all courses, but also the added property for accounting for seats.

Note the additional logic to decrease the number of allowed seats after another enrolment.

Extensibility in Implementation

In this example, GetTestCourses simulates populating a schedule of available classes.
A common approach would be to define a new class from which to instantiate an array of objects representing courses.
However, since we have two different course types – online and in-person, that approach proves too limiting and inflexible to future needs for more course types.

However, since the collection to receive courses uses the same contract implementing by all courses, it can receive all course types – online and in-person.

Similarly, when iterating through the schedule of classes and simulating enrollment of each class, notice the loop doesn’t care whether or not the course is online or in-person. Also, this allows for future course types (hybrid) to be added, allowing for further customization of a course without requiring any changes to this code.

Finally, how does implementation leverage differences in course types?

A simple check of the course’s contract allows the user to place such courses into a temporary variable scoped to that block and another line is added to the report.