C# Interface And Why Interface

Preface

Interface implementation is one of the most important features in C# to implement object-oriented programming. However, based on my previous experience in reading online articles (including programming books) for interfaces, most of the time those articles have pointed out how to use interfaces, but never mentioned WHY very clearly.

So, I want to share some of my experience, why the Interface is useful in daily development.

(Disclaimer: This is just my own experience in using Interface, I'm not saying it is the only way to achieve it or there only can be achieved by Interface).

Example Study Case: Employee in a company

C# Interface

Consider the following scenario, a company has 3 types of employees: ExecutiveManager, and C-suite level employee.

Executive has a name, designation and KPI. This is the example class for employee.

public class Executive {
    public string Name {
        get;
        set;
    }
    public string Designation {
        get;
        set;
    }
    public int KPI {
        get;
        set;
    }
}

Manager has the same thing with the Executive, but they have extra rights to evaluate Executive level employee only. This is the example class for manager.

public string Name {
    get;
    set;
}
public string Designation {
    get;
    set;
}
public int KPI {
    get;
    set;
}
public Executive EvaluateSubordinate(Executive executive) {
    Random random = new Random();
    executive.KPI = random.Next(40, 100);
    return executive;
}

A C-Suite level employee has only name and designation, but not KPI. We presume that their KPI is tied to company stock performances or other performances. C-Suite level employees also have the rights to evaluate Manager level employees only, and furthermore, they have the right to terminate any underperforming employee. This is the example class for C-Suite.

public class CSuite {
    public string Name {
        get;
        set;
    }
    public string Designation {
        get;
        set;
    }
    public Manager EvaluateSubordinate(Manager manager) {
        Random random = new Random();
        manager.KPI = random.Next(60, 100);
        return manager;
    }
    public void TerminateExecutive(Executive executive) {
        Console.WriteLine($ "Employee {executive.Name} with KPI {executive.KPI} has been terminated because of KPI below 70");
    }
    public void TerminateManager(Manager manager) {
        Console.WriteLine($ "Employee {manager.Name} with KPI {manager.KPI} has been terminated because of KPI below 70");
    }
}

Please take note that

  1. Even the Manager and CSuite class have an EvaluateSubordinate method, but they accept different types of arguments.
  2. CSuite has two TerminateExecutive functions, that accept different types of arguments.

Consider that we want to group all the class in one list, and iterate each employee to perform following tasks.

  1. Display their name and designation
  2. Evaluate their KPI by their corresponding supervisor
  3. C-Suite level employee will terminate those who have KPI less than 70.

Something like this:

And now in my main program, I'm initializing all my employees.

Executive executive = new Executive() { Name = "Alice", Designation = "Programmer"}; 
Manager manager = new Manager() { Name = "Bob", Designation = "Sales Manager"};
CSuite cSuite = new CSuite() { Name = "Daisy", Designation = "CFO" };

Then now I immediately encounter my first problem, I cannot group all these employees together, since they share different class types. 

Benefit #1 of Interface: Act as Generic Class

So now we reach the first reason if this article why we need Interface, group all the different class together.

Since all different employees have name and designation, I will create my generic Interface that contains these two properties, which this Interface will hold the responsibility to group all employees together. I called it IEmployee

public interface IEmployee {
    string Name {
        get;
        set;
    }
    string Designation {
        get;
        set;
    }
}

Second, since only Executive and Manager class employees has KPI to be evaluated, so I created an Interface called IEvaluatedEmployee, which only has one property : KPI. Please take note that my IEvaluatedEmployee Interface also Implements IEmployee Interface. This means that whichever class that implements this Interface, will also have the properties of IEmployee (has name and designation).

public interface IEvaluatedEmployee: IEmployee {
    int KPI {
        get;
        set;
    }
  }
}

I created another Interface called IManagementLevelEmployee, which indicates this interface has the right to manage people, aka, evaluates employees for their KPI for our example.

public interface IManagementLevelEmployee: IEmployee {
    IEvaluatedEmployee EvaluateSubordinate(IEvaluatedEmployee employee);
}

Finally, we knew that only C-Suite has the privilege to terminate employee, so I created an Interface called ICSuite_Privilege, with the terminate employee function.

public interface ICSuite_Privilege: IEmployee {
    bool TerminateEmployee(IEvaluatedEmployee executive);
}

I’m done with the Interface, so now I will let my concrete class to implements those Interfaces.

For Executive class:

public class Executive: IEvaluatedEmployee {
    public string Name {
        get;
        set;
    }
    public string Designation {
        get;
        set;
    }
    public int KPI {
        get;
        set;
    }
}

For Manager class:

public class Manager: IManagementLevelEmployee, IEvaluatedEmployee {
    public string Name {
        get;
        set;
    }
    public string Designation {
        get;
        set;
    }
    public int KPI {
        get;
        set;
    }
    public IEvaluatedEmployee EvaluateSubordinate(IEvaluatedEmployee evaluatedemployee) {
        Random random = new Random();
        evaluatedemployee.KPI = random.Next(40, 100);
        return evaluatedemployee;
    }
}

Please take note that Manager class implements IManagementLevelEmployee and IEvaluatedEmployee together, so this indicates that employees belonging to this class have the right to manage and evaluate other employees, but at the same time will also be managed and evaluated by someone else.  

Finally our C-Suite class,

public class CSuite: IManagementLevelEmployee, ICSuite_Privilege {
    public string Name {
        get;
        set;
    }
    public string Designation {
        get;
        set;
    }
    public IEvaluatedEmployee EvaluateSubordinate(IEvaluatedEmployee Manager) {
        Random random = new Random();
        Manager.KPI = random.Next(60, 100);
        return Manager;
    }
    public bool TerminateEmployee(IEvaluatedEmployee evemp) {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine($ "Employee {evemp.Name} with KPI {evemp.KPI} has been terminated because of KPI below 70");
        Console.ForegroundColor = ConsoleColor.White;
        return true;
    }
}

The Class Diagram after all classes implement Interfaces will look like this:

C# Interface

So now in the main program, I can group all three different class, under IEmployee and iterate each to display their info.

employees.Add(new Executive() {
    Name = "Alex", Designation = "Programmer"
});
employees.Add(new Manager() {
    Name = "Bob", Designation = "Sales Manager"
});
employees.Add(new CSuite() {
    Name = "Daisy", Designation = "CFO"
});
#region Display Employees Info
Console.WriteLine("-----Display Employee's Information-----");
foreach(IEmployee employee in employees) {
    DisplayEmployeeInfo(employee);
}
Console.WriteLine();
#endregion
static void DisplayEmployeeInfo(IEmployee employee) {
    Console.WriteLine($ "{employee.Name} is a {employee.Designation}");
}

The benefit of Interface is not only limited to group related classes together, it also provides the flexibility in writing a function. Considering the terminate function by C-Suite Employee, we only need to write one function TerminateEmployee that accepts arguments with type IEvaluatedEmployee (which cater for Executive and Manager), instead of my above mentioned original two functions to terminate Executive and Manager respectively.

public bool TerminateEmployee(IEvaluatedEmployee evemp) {
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine($ "Employee {evemp.Name} with KPI {evemp.KPI} has been terminated because of KPI below 70");
    Console.ForegroundColor = ConsoleColor.White;
    return true;
}

Benefit #2 of Interface: Contact Binding and Class Empowerment

Many people consider Interface as a ‘contract’ between classes. Consider a real life example, a factory owner signs a contract with an investor that the factory will produce 100 shoes in 1 month. Factory MUST produce 100 shoes to the investor, and failing to do so will cause a penalty.   

public class CSuite :  IManagementLevelEmployee, ICSuite_Privilege

For example, CSuite class has two Interfaces IManagementLevelEmployee and ICSuite_Privilege. This is a ‘Contact’ to force this class must have all the features of these two Interfaces (Evaluate and Terminate Employee), failed to do so, the compiler will return a (penalty in the real world case).

Let's say in future, a new class called “Board” to be introduced, so we can assign a similar privilege to Board class, to ensure they have the power as C-Suite do. With this we can ensure all Board class will have the terminate function. With this feature, a programmer can understand the responsibility of each class quickly, by looking at the Inteface/s each class implemented.

public class Board : ICSuite_Privilege

Benefit #3 of Interface: Multiple Inheritance to perform responsibility segregation

You may notice the IManagementLevelEmployee Interface has a function called EvaluateSubordinate, and the parameter it accept is IEvaluatedEmployee instead of IEmployee.

IEvaluatedEmployee EvaluateSubordinate(IEvaluatedEmployee employee);//why IEvaluatedEmployee 
 
IEvaluatedEmployee EvaluateSubordinate(IEmployee employee);//Instead of IEmployee

The EvaluateSubordinate function will still work if it accept IEmployee, since Executive and Manager class also implement IEmployee, why I’m using IEvaluatedEmployee instead?

This is because, in our case

  1. C-Suite level also implement IEmployee
  2. But C-Suite level do not evaluate by anyone
  3. And what is the indicator for employee who will be evaluated? For our case, it is they have KPI.

So, in order to fulfill every requirement, I created an Interface called IEvaluatedEmployee, that have KPI property, and at the same time it implements IEmployee. So this means whoever implements this Interface (Executive and Manager), will not only have KPI, but also have all the signatures of IEmployee (name and designation).

public interface IEvaluatedEmployee: IEmployee {
    int KPI {
        get;
        set;
    }
}
public class Executive: IEvaluatedEmployee
public class Manager: IManagementLevelEmployee, IEvaluatedEmployee
public class CSuite: IManagementLevelEmployee, ICSuite_Privilege //not implements IEvaluatedEmployee

But, CSuite class do not implement IEvaluatedEmployee Interface, so for the EvaluateSubordinate function, we can prevent object from CSuite class being passed into and evaluated, since we have set this kind of contact and restriction, by using Interface. This can keep the business logic of our code always consistent.

Benefit #4 of Interface: Impact Analysis

And let's say in future, the company’s board director comes out with a new policy for the company

  1. C-Suite employee need to be evaluated
  2. Introduce two more parameters a and b for the evaluation

Since my example is a small program, I know where to change my code in a split of seconds without any error. However, in real life the system can be huge and very complex, without Interface it is very difficult to maintain or apply changes.

For the sake of demo, to implement the two company’s new policy, I will

  1. Let the CSuite class implement IEvaluatedEmployee Interface
    public class CSuite :  IManagementLevelEmployee, ICSuite_Privilege, IEvaluatedEmployee
    

    2. Introduce two more parameters a and b for EvaluateSubordinate in Interface IManagementLevelEmployee

    public interface IManagementLevelEmployee : IEmployee
       {
           IEvaluatedEmployee EvaluateSubordinate(IEvaluatedEmployee employee, string a, string b);//add two more parameters a and b
       }

    The Visual Studio will immediately give me the error warning that indicates my CSuite does not implement IEvaluatedEmployee (missing property of int KPI ), and my Manager and CSuite class do not correctly implement IManagementLevelEmployee Interface ( EvaluateSubordinate function needs two new parameters).

C# Interface

Imagine without Interfaces, a programmer will not be able to identify all the parts that need to be changed, and only realize it after the system has gone live. So again, Interface can make sure our code is always consistent with the latest business logic.

Benefit #5 Abstraction for Planning

In real life, normally there will be more than one developer to develop the project. And sometimes we have the start developing even before the finalize business requirement. So, with Interfaces, the lead programmer or solution architect are able to standardize the features of each class. By using the same example, the tech lead might not know what is the exact business logic to evaluate an employee, but by using the Interface, he/she can ensure all programmer that develop Manager or Csuite class must contains EvaluateSubordinate function, and also have Name and Designation for all employee etc, by stating it in the Interface.

Benefit #6 Unit Test

Last but not least, or in fact this might be one of the most important reasons to implement Interface, for Unit Test. This benefit is quite similar with Benefit #5, since a lot of companies applied Test Driven Development (TDD) methodology in their software development process, so during the planning state, unit test setup is very important before the actual development kick start.

Let say there is a function called CheckEmployee() for Executive and Manager class, and this class will login to database and check the info of the employee, before we can terminate it.

public class Executive: IEvaluatedEmployee {
    public string Name {
        get;
        set;
    }
    public string Designation {
        get;
        set;
    }
    public int KPI {
        get;
        set;
    }
    public bool CheckEmployee() {
        //pretend that we are calling database here
        return false;
    }
}

But for the Unit Test, we may be unable to connect to the real production database, or not allowed to do so in case we may jeopardize the production data, so for the unit test we will use a mockup feature to assume the login to database and check employee function pass.  The Unit Test code will look like this (I’m using Moq framework)

[TestMethod]
public void TestMethod1() {
    Mock < IEvaluatedEmployee > EvEmp = new Mock < IEvaluatedEmployee > ();
    EvEmp.Setup(x => x.CheckEmployee()).Returns(true);
    CSuite obje = new CSuite();
    Assert.AreEqual(obje.TerminateEmployee(EvEmp.Object), true);
}

We used the Interface IEvaluatedEmployee to mockup the Executive class, and mock the CheckEmployee function to always return true.

If we do not have Interface and use the real Executive class to do the mockup, visual studio will return an error. This is because the system cannot override the concrete class function to make it always return true or certain mockup data.

Conclusion

I hope this article can help you to understand the importance of Interface, and you know when and why you should apply it in your programming career.

All the source code can be found via my Github.


Similar Articles