-
C# Abstraction
-
Abstraction in C# allows us to hide the complex implementation details and expose only the essential functionality. Think of your TV remote - you just press buttons to make things happen, right? You don't need to know how the signals work inside.
When applied to a scenario like managing employees, you can use abstraction to define a general contract for employee-related operations while hiding the specific implementation details of different types of employees (like managers, developers, etc.).
In C#, abstraction is typically achieved using abstract classes or interfaces. Let’s look at how we can define abstraction with the example of an Employee class hierarchy.
Example 1: Using Abstract Classes for Employees
Here, we will create an abstract class
Employee
with abstract methods that each specific type of employee must implement.using System; // Abstract class public abstract class Employee { // Abstract method for calculating salary public abstract double CalculateSalary(); // Method to display employee details public void DisplayDetails() { Console.WriteLine("Employee details are being displayed."); } } // Derived class for full time employees public class FullTimeEmployee : Employee { public double MonthlySalary { get; set; } public FullTimeEmployee(double monthlySalary) { MonthlySalary = monthlySalary; } // Implement the CalculateSalary method for the full time employees public override double CalculateSalary() { return MonthlySalary; } } // Derived class for part time employees public class PartTimeEmployee : Employee { public double HourlyRate { get; set; } public double HoursWorked { get; set; } public PartTimeEmployee(double hourlyRate, double hoursWorked) { HourlyRate = hourlyRate; HoursWorked = hoursWorked; } // Implement the CalculateSalary method for part-time employees public override double CalculateSalary() { return HourlyRate * HoursWorked; } } public class Program { public static void Main() { Employee fullTime = new FullTimeEmployee(4000); Employee partTime = new PartTimeEmployee(20, 100); Console.WriteLine("Full-Time Employee Salary: $" + fullTime.CalculateSalary());// Outputs: 4000 Console.WriteLine("Part-Time Employee Salary: $" + partTime.CalculateSalary());// Outputs: 2000 } }
Explanation:
- Employee is an abstract class which includes an abstract method CalculateSalary(), which forces all the derived classes (like
FullTimeEmployee
and PartTimeEmployee) to provide their own implementation of this method. - The method
DisplayDetails()
is a regular method with the common implementation for all employees. - FullTimeEmployee class calculates salary based on a fixed monthly salary, while the PartTimeEmployee class calculates salary based on hourly rates and the number of hours worked.
Example 2: Using Interfaces for Employees
An interface is a contract that defines methods without implementing them. Any class that implements an interface must provide its own implementation of those methods. Using the similar Employee hierarchy example, you can use an interface to define the contract for employee-related functionality, where each employee type must implement the methods.
using System; // Interface public interface IEmployee { double CalculateSalary(); void DisplayDetails(); } // Full-time employee implementing IEmployee interface public class FullTimeEmployee : IEmployee { public double MonthlySalary { get; set; } public FullTimeEmployee(double monthlySalary) { MonthlySalary = monthlySalary; } // Implement the CalculateSalary() method for the full-time employees public double CalculateSalary() { return MonthlySalary; } // Implement the DisplayDetails method for the full-time employees public void DisplayDetails() { Console.WriteLine("Full-Time Employee: Monthly Salary = $" + MonthlySalary); } } // Part-time employee implementing IEmployee interface public class PartTimeEmployee : IEmployee { public double HourlyRate { get; set; } public double HoursWorked { get; set; } public PartTimeEmployee(double hourlyRate, double hoursWorked) { HourlyRate = hourlyRate; HoursWorked = hoursWorked; } // Implement the CalculateSalary() method for the part-time employees public double CalculateSalary() { return HourlyRate * HoursWorked; } // Implement the DisplayDetails() method public void DisplayDetails() { Console.WriteLine("Part-Time Employee: Hourly Rate = $" + HourlyRate + ", Hours Worked = " + HoursWorked); } } public class Program { public static void Main() { IEmployee fullTime = new FullTimeEmployee(5000); IEmployee partTime = new PartTimeEmployee (50, 100); fullTime.DisplayDetails(); // Outputs: Full-Time Employee: Monthly Salary = $5000 Console.WriteLine("Full-Time Salary: $" + fullTime.CalculateSalary()); // Outputs: 5000 partTime.DisplayDetails(); // Outputs: Part-Time Employee: Hourly Rate = $50, Hours Worked = 100 Console.WriteLine("Part-Time Salary: $" + partTime.CalculateSalary()); // Outputs: 5000 } }
Explanation:
- IEmployee is an interface that defines the methods
CalculateSalary()
andDisplayDetails()
. Any class that implements this IEmployee interface must provide its own implementation of these two methods. - FullTimeEmployee and PartTimeEmployee implement the
IEmployee
interface and provide their own specific logic for calculating salary and displaying employee’s details. .
Benefits of Abstraction in the Employee Example:
- Flexibility:New employee types (such as contractors or interns) can be easily added without altering the existing code. Simply implement the
IEmployee
interface or extend theEmployee
abstract class to introduce new variations. - Loose Coupling: The client code doesn't need to be concerned with the specific type of employee. It interacts only with the
IEmployee
interface or theEmployee
abstract class, making the system more modular and adaptable to future changes. - Code Reusability: Common functionality, like the
DisplayDetails()
method, can be reused by all employee types. At the same time, each specific employee type can implement its own salary calculation logic, ensuring that unique behaviors are preserved while shared code is reused.
Real-World Example 🌍
Think of a coffee machine:
- You press a button → Get coffee
- You don't need to know:
- How water is heated
- How beans are ground
- How milk is frothed
That's exactly what we're doing with our code! The complex details are hidden, but everything still works perfectly.
Conclusion:
Abstraction in C# enables you to focus on what an employee does (such as calculating salary or displaying details) while concealing the underlying implementation details (like whether the employee is full-time or part-time). You can implement abstraction using abstract classes or interfaces based on the specific needs of your application, providing flexibility and maintainability in your code design.
- Employee is an abstract class which includes an abstract method CalculateSalary(), which forces all the derived classes (like