Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Interfaces

Define contracts with interfaces for flexible, maintainable code.

Interfaces define contracts that classes must follow. They specify what methods a class must implement without specifying how they should be implemented. This allows for polymorphism and loose coupling.

An interface is a contract that specifies what methods a class must implement. It defines the “what” but not the “how”.

  • Polymorphism - Different classes can be used interchangeably
  • Loose Coupling - Depend on abstractions, not concrete classes
  • Flexibility - Easy to swap implementations
  • Testability - Easy to create mock implementations
  • Multiple Inheritance - Classes can implement multiple interfaces

Python doesn’t have explicit interfaces like Java, but uses:

  • Abstract Base Classes (ABC) - Similar to interfaces
  • Protocols - Structural subtyping (duck typing)
  • ABC with @abstractmethod - Enforces method implementation
interface_abc.py
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
"""Interface-like abstract class"""
@abstractmethod
def process_payment(self, amount: float) -> bool:
"""Process a payment - must be implemented"""
pass
@abstractmethod
def refund(self, transaction_id: str) -> bool:
"""Process a refund - must be implemented"""
pass
def validate_amount(self, amount: float) -> bool:
"""Concrete method - shared by all implementations"""
return amount > 0
class CreditCardProcessor(PaymentProcessor):
"""Implements PaymentProcessor interface"""
def __init__(self, api_key: str):
self.api_key = api_key
def process_payment(self, amount: float) -> bool:
"""Implement required method"""
if not self.validate_amount(amount):
return False
print(f"Processing ${amount} via credit card")
return True
def refund(self, transaction_id: str) -> bool:
"""Implement required method"""
print(f"Refunding transaction {transaction_id} via credit card")
return True
class PayPalProcessor(PaymentProcessor):
"""Implements PaymentProcessor interface"""
def process_payment(self, amount: float) -> bool:
"""Implement required method"""
if not self.validate_amount(amount):
return False
print(f"Processing ${amount} via PayPal")
return True
def refund(self, transaction_id: str) -> bool:
"""Implement required method"""
print(f"Refunding transaction {transaction_id} via PayPal")
return True
# Usage - polymorphism
def checkout(processor: PaymentProcessor, amount: float):
"""Works with any PaymentProcessor implementation"""
return processor.process_payment(amount)
credit_card = CreditCardProcessor("api_key_123")
paypal = PayPalProcessor()
checkout(credit_card, 100.0) # Works
checkout(paypal, 100.0) # Works
Output
Processing $100.0 via credit card
Processing $100.0 via PayPal

Classes can implement multiple interfaces:

multiple_interfaces.py
from abc import ABC, abstractmethod
class Flyable(ABC):
@abstractmethod
def fly(self):
pass
class Swimmable(ABC):
@abstractmethod
def swim(self):
pass
class Duck(Flyable, Swimmable):
"""Duck implements multiple interfaces"""
def fly(self):
return "Flying through the air"
def swim(self):
return "Swimming in water"
def quack(self):
return "Quack!"
duck = Duck()
print(duck.fly()) # "Flying through the air"
print(duck.swim()) # "Swimming in water"
print(duck.quack()) # "Quack!"
Output
Flying through the air
Swimming in water
Quack!
notification_interface.py
from abc import ABC, abstractmethod
class NotificationService(ABC):
"""Interface for notification services"""
@abstractmethod
def send(self, recipient: str, message: str) -> bool:
"""Send notification - must be implemented"""
pass
@abstractmethod
def can_send(self, recipient: str) -> bool:
"""Check if notification can be sent"""
pass
class EmailService(NotificationService):
"""Email notification implementation"""
def send(self, recipient: str, message: str) -> bool:
if not self.can_send(recipient):
return False
print(f"Sending email to {recipient}: {message}")
return True
def can_send(self, recipient: str) -> bool:
return "@" in recipient
class SMSService(NotificationService):
"""SMS notification implementation"""
def send(self, recipient: str, message: str) -> bool:
if not self.can_send(recipient):
return False
print(f"Sending SMS to {recipient}: {message[:50]}...")
return True
def can_send(self, recipient: str) -> bool:
return recipient.startswith("+")
class NotificationManager:
"""Manages multiple notification services"""
def __init__(self):
self.services: list[NotificationService] = []
def add_service(self, service: NotificationService):
"""Add a notification service"""
self.services.append(service)
def broadcast(self, recipient: str, message: str):
"""Send message through all services"""
for service in self.services:
if service.can_send(recipient):
service.send(recipient, message)
# Usage
manager = NotificationManager()
manager.add_service(EmailService())
manager.add_service(SMSService())
manager.broadcast("user@example.com", "Your order has shipped!")
manager.broadcast("+1234567890", "Your order has shipped!")
Output
Sending email to user@example.com: Your order has shipped!
Sending SMS to +1234567890: Your order has shipped!
Diagram

Use interfaces when:

  • You want to define a contract that multiple classes can follow
  • You need polymorphism - treat different classes the same way
  • You want loose coupling - depend on abstractions
  • You need multiple inheritance of behavior (not state)
  • You want to make code more testable with mock implementations

Examples:

  • Payment processors (different payment methods)
  • Notification services (email, SMS, push)
  • Data access layers (different databases)
  • Storage services (local, cloud, database)
  • Authentication providers (OAuth, JWT, etc.)