Introduction
Abstraction is one of the four fundamental principles of object-oriented programming (OOP). It involves the process of hiding the implementation details and showing only the essential features of an object. Abstraction focuses on the what rather than the how. It helps in reducing complexity by allowing the user to interact with an object at a higher level of abstraction.
In C#, abstraction is achieved using abstract classes and interfaces.
Abstract Classes
An abstract class is a class that cannot be instantiated and is typically used as a base class. It can contain abstract methods (without implementation) and non-abstract methods (with implementation). Abstract methods must be implemented by derived classes.
Syntax
public abstract class AbstractClassName
{
// Abstract method (no implementation)
public abstract void AbstractMethod();
// Non-abstract method (with implementation)
public void RegularMethod()
{
// Method body
}
}
Example
Let’s consider an example to demonstrate the concept of an abstract class.
using System;
namespace AbstractionExample
{
// Abstract base class
public abstract class Shape
{
// Abstract method (must be implemented by derived classes)
public abstract void Draw();
// Non-abstract method (can be inherited or overridden)
public void Display()
{
Console.WriteLine("Displaying the shape.");
}
}
// Derived class
public class Circle : Shape
{
// Implementation of the abstract method
public override void Draw()
{
Console.WriteLine("Drawing a circle.");
}
}
// Derived class
public class Rectangle : Shape
{
// Implementation of the abstract method
public override void Draw()
{
Console.WriteLine("Drawing a rectangle.");
}
}
class Program
{
static void Main(string[] args)
{
Shape shape;
shape = new Circle();
shape.Draw(); // Outputs: Drawing a circle.
shape.Display(); // Outputs: Displaying the shape.
shape = new Rectangle();
shape.Draw(); // Outputs: Drawing a rectangle.
shape.Display(); // Outputs: Displaying the shape.
}
}
}
Output
Drawing a circle.
Displaying the shape.
Drawing a rectangle.
Displaying the shape.
Interfaces
An interface is a contract that defines a set of methods and properties that the implementing class must provide. Interfaces do not contain any implementation. A class can implement multiple interfaces, providing a way to achieve multiple inheritance.
Syntax
public interface InterfaceName
{
// Method signature
void MethodName();
// Property signature
int PropertyName { get; set; }
}
Example
Let’s consider an example to demonstrate the concept of an interface.
using System;
namespace AbstractionExample
{
// Interface
public interface IDrawable
{
void Draw();
}
// Implementing the interface
public class Circle : IDrawable
{
public void Draw()
{
Console.WriteLine("Drawing a circle.");
}
}
// Implementing the interface
public class Rectangle : IDrawable
{
public void Draw()
{
Console.WriteLine("Drawing a rectangle.");
}
}
class Program
{
static void Main(string[] args)
{
IDrawable drawable;
drawable = new Circle();
drawable.Draw(); // Outputs: Drawing a circle.
drawable = new Rectangle();
drawable.Draw(); // Outputs: Drawing a rectangle.
}
}
}
Output
Drawing a circle.
Drawing a rectangle.
Benefits of Abstraction
- Simplification: Abstraction reduces complexity by hiding unnecessary details and exposing only the relevant features.
- Reusability: Abstract classes and interfaces promote code reuse by defining common methods and properties that can be shared across multiple classes.
- Maintainability: Abstraction helps in maintaining the code by separating the implementation from the interface. Changes in implementation do not affect the interface.
- Flexibility: Interfaces provide a way to achieve multiple inheritance, allowing a class to implement multiple interfaces.
Real-World Example
Consider a real-world example of a banking system where different types of accounts share common features but have their own specific behaviors.
Abstract Class Example
using System;
namespace BankingExample
{
// Abstract base class
public abstract class BankAccount
{
public string AccountNumber { get; set; }
public double Balance { get; set; }
public BankAccount(string accountNumber, double initialBalance)
{
AccountNumber = accountNumber;
Balance = initialBalance;
}
// Abstract method to be implemented by derived classes
public abstract void CalculateInterest();
// Non-abstract method
public void Deposit(double amount)
{
Balance += amount;
Console.WriteLine($"Deposited {amount}. New balance: {Balance}");
}
// Non-abstract method
public void Withdraw(double amount)
{
if (amount <= Balance)
{
Balance -= amount;
Console.WriteLine($"Withdrew {amount}. New balance: {Balance}");
}
else
{
Console.WriteLine("Insufficient balance.");
}
}
}
// Derived class
public class SavingsAccount : BankAccount
{
public SavingsAccount(string accountNumber, double initialBalance)
: base(accountNumber, initialBalance)
{
}
// Implementation of the abstract method
public override void CalculateInterest()
{
double interest = Balance * 0.04;
Balance += interest;
Console.WriteLine($"Interest added. New balance: {Balance}");
}
}
// Derived class
public class CheckingAccount : BankAccount
{
public CheckingAccount(string accountNumber, double initialBalance)
: base(accountNumber, initialBalance)
{
}
// Implementation of the abstract method
public override void CalculateInterest()
{
// No interest for checking accounts
Console.WriteLine("No interest for checking accounts.");
}
}
class Program
{
static void Main(string[] args)
{
BankAccount savings = new SavingsAccount("S123", 1000);
savings.CalculateInterest(); // Outputs: Interest added. New balance: 1040
savings.Deposit(500);
savings.Withdraw(300);
BankAccount checking = new CheckingAccount("C123", 1000);
checking.CalculateInterest(); // Outputs: No interest for checking accounts.
checking.Deposit(500);
checking.Withdraw(300);
}
}
}
Output
Interest added. New balance: 1040
Deposited 500. New balance: 1540
Withdrew 300. New balance: 1240
No interest for checking accounts.
Deposited 500. New balance: 1500
Withdrew 300. New balance: 1200
Interface Example
using System;
namespace BankingExample
{
// Interface
public interface IAccount
{
void Deposit(double amount);
void Withdraw(double amount);
void CalculateInterest();
}
// Implementing the interface
public class SavingsAccount : IAccount
{
public string AccountNumber { get; set; }
public double Balance { get; set; }
public SavingsAccount(string accountNumber, double initialBalance)
{
AccountNumber = accountNumber;
Balance = initialBalance;
}
public void Deposit(double amount)
{
Balance += amount;
Console.WriteLine($"Deposited {amount}. New balance: {Balance}");
}
public void Withdraw(double amount)
{
if (amount <= Balance)
{
Balance -= amount;
Console.WriteLine($"Withdrew {amount}. New balance: {Balance}");
}
else
{
Console.WriteLine("Insufficient balance.");
}
}
public void CalculateInterest()
{
double interest = Balance * 0.04;
Balance += interest;
Console.WriteLine($"Interest added. New balance: {Balance}");
}
}
// Implementing the interface
public class CheckingAccount : IAccount
{
public string AccountNumber { get; set; }
public double Balance { get; set; }
public CheckingAccount(string accountNumber, double initialBalance)
{
AccountNumber = accountNumber;
Balance = initialBalance;
}
public void Deposit(double amount)
{
Balance += amount;
Console.WriteLine($"Deposited {amount}. New balance: {Balance}");
}
public void Withdraw(double amount)
{
if (amount <= Balance)
{
Balance -= amount;
Console.WriteLine($"Withdrew {amount}. New balance: {Balance}");
}
else
{
Console.WriteLine("Insufficient balance.");
}
}
public void CalculateInterest()
{
// No interest for checking accounts
Console.WriteLine("No interest for checking accounts.");
}
}
class Program
{
static void Main(string[] args)
{
IAccount savings = new SavingsAccount("S123", 1000);
savings.CalculateInterest(); // Outputs: Interest added. New balance: 1040
savings.Deposit(500);
savings.Withdraw(300);
IAccount checking = new CheckingAccount("C123", 1000);
checking.CalculateInterest(); // Outputs: No interest for checking accounts.
checking.Deposit(500);
checking.Withdraw(300);
}
}
}
Output
Interest added. New
balance: 1040
Deposited 500. New balance: 1540
Withdrew 300. New balance: 1240
No interest for checking accounts.
Deposited 500. New balance: 1500
Withdrew 300. New balance: 1200
Conclusion
Abstraction in C# is a powerful concept that helps in simplifying complex systems by focusing on high-level operations while hiding the underlying details. Abstract classes and interfaces are the primary tools for achieving abstraction. By using these tools, you can create more modular, reusable, and maintainable code. Understanding abstraction is crucial for designing robust and flexible object-oriented applications.