Isaac.

Interfaces vs Abstract Classes

Choose between interfaces and abstract classes effectively.

By EMEPublished: February 20, 2025
interfacesabstract classescontractsoop

A Simple Analogy

Interfaces are like contracts; abstract classes are like templates. Interfaces say "do this," abstract classes say "here's how."


When to Use Each

Use Interfaces when:

  • Defining a contract
  • Multiple unrelated classes implement it
  • No shared implementation

Use Abstract Classes when:

  • Sharing code between related classes
  • Controlling access (protected/private)
  • Need non-public members

Interface Example

public interface IPaymentProcessor
{
    Task<bool> ProcessPaymentAsync(decimal amount);
    Task<bool> RefundAsync(string transactionId);
}

public class CreditCardProcessor : IPaymentProcessor
{
    public async Task<bool> ProcessPaymentAsync(decimal amount)
    {
        // Implementation
        return true;
    }
    
    public async Task<bool> RefundAsync(string transactionId)
    {
        // Implementation
        return true;
    }
}

public class PayPalProcessor : IPaymentProcessor
{
    public async Task<bool> ProcessPaymentAsync(decimal amount)
    {
        // Different implementation
        return true;
    }
    
    public async Task<bool> RefundAsync(string transactionId)
    {
        // Different implementation
        return true;
    }
}

Abstract Class Example

public abstract class PaymentProcessor
{
    protected string ApiKey { get; set; }
    
    public abstract Task<bool> ProcessPaymentAsync(decimal amount);
    
    protected virtual void LogTransaction(string id)
    {
        Console.WriteLine($"Transaction: {id}");
    }
}

public class CreditCardProcessor : PaymentProcessor
{
    public override async Task<bool> ProcessPaymentAsync(decimal amount)
    {
        LogTransaction($"CC-{amount}");
        return true;
    }
}

Key Differences

Interfaces:
- All members are public
- No implementation (before C# 8.0)
- Multiple inheritance allowed
- Define "what"

Abstract Classes:
- Can have protected/private
- Can have implementation
- Single inheritance only
- Define "how"

Best Practices

  1. Prefer interfaces: For flexibility
  2. Use abstract: For shared implementation
  3. Small interfaces: Single responsibility
  4. Dependency injection: Use interface types
  5. Documentation: Document intent clearly

Related Concepts

  • Composition over inheritance
  • Dependency injection
  • SOLID principles
  • Design patterns

Summary

Use interfaces for contracts and abstract classes for shared behavior. Prefer interfaces when possible for flexibility.