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.
What are Interfaces?
Section titled “What are Interfaces?”An interface is a contract that specifies what methods a class must implement. It defines the “what” but not the “how”.
Why Use Interfaces?
Section titled “Why Use Interfaces?”- 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 Interfaces
Section titled “Python 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
💡 Tip: Click dropdown to switch between languages
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 - polymorphismdef 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) # Workscheckout(paypal, 100.0) # WorksProcessing $100.0 via credit cardProcessing $100.0 via PayPalfrom typing import Protocol
class PaymentProcessor(Protocol): """Protocol - structural subtyping"""
def process_payment(self, amount: float) -> bool: """Process a payment""" ...
def refund(self, transaction_id: str) -> bool: """Process a refund""" ...
class CreditCardProcessor: """Implements PaymentProcessor protocol"""
def process_payment(self, amount: float) -> bool: print(f"Processing ${amount} via credit card") return True
def refund(self, transaction_id: str) -> bool: print(f"Refunding transaction {transaction_id} via credit card") return True
# Protocol doesn't enforce - duck typingdef checkout(processor: PaymentProcessor, amount: float): return processor.process_payment(amount)
credit_card = CreditCardProcessor()checkout(credit_card, 100.0) # Works// Interface definitionpublic interface PaymentProcessor { // Abstract methods (implicitly public and abstract) boolean processPayment(double amount); boolean refund(String transactionId);
// Default method (Java 8+) default boolean validateAmount(double amount) { return amount > 0; }
// Static method (Java 8+) static String getProcessorType() { return "Payment Processor"; }}
// Implementationpublic class CreditCardProcessor implements PaymentProcessor { private String apiKey;
public CreditCardProcessor(String apiKey) { this.apiKey = apiKey; }
@Override public boolean processPayment(double amount) { if (!validateAmount(amount)) { return false; } System.out.println("Processing $" + amount + " via credit card"); return true; }
@Override public boolean refund(String transactionId) { System.out.println("Refunding transaction " + transactionId + " via credit card"); return true; }}
public class PayPalProcessor implements PaymentProcessor { @Override public boolean processPayment(double amount) { if (!validateAmount(amount)) { return false; } System.out.println("Processing $" + amount + " via PayPal"); return true; }
@Override public boolean refund(String transactionId) { System.out.println("Refunding transaction " + transactionId + " via PayPal"); return true; }}
// Usage - polymorphismpublic class Main { public static void checkout(PaymentProcessor processor, double amount) { processor.processPayment(amount); }
public static void main(String[] args) { PaymentProcessor creditCard = new CreditCardProcessor("api_key_123"); PaymentProcessor paypal = new PayPalProcessor();
checkout(creditCard, 100.0); // Works checkout(paypal, 100.0); // Works }}Processing $100.0 via credit cardProcessing $100.0 via PayPal// Interface definitioninterface PaymentProcessor { processPayment(amount: number): boolean; refund(transactionId: string): boolean;
// TypeScript doesn't have default methods in interfaces // but you can use abstract classes for that}
// Implementationclass CreditCardProcessor implements PaymentProcessor { private apiKey: string;
constructor(apiKey: string) { this.apiKey = apiKey; }
processPayment(amount: number): boolean { if (!this.validateAmount(amount)) { return false; } console.log(`Processing $${amount} via credit card`); return true; }
refund(transactionId: string): boolean { console.log(`Refunding transaction ${transactionId} via credit card`); return true; }
private validateAmount(amount: number): boolean { return amount > 0; }}
class PayPalProcessor implements PaymentProcessor { processPayment(amount: number): boolean { if (!this.validateAmount(amount)) { return false; } console.log(`Processing $${amount} via PayPal`); return true; }
refund(transactionId: string): boolean { console.log(`Refunding transaction ${transactionId} via PayPal`); return true; }
private validateAmount(amount: number): boolean { return amount > 0; }}
// Usage - polymorphismfunction checkout(processor: PaymentProcessor, amount: number): void { processor.processPayment(amount);}
const creditCard = new CreditCardProcessor("api_key_123");const paypal = new PayPalProcessor();
checkout(creditCard, 100.0); // Workscheckout(paypal, 100.0); // WorksProcessing $100 via credit cardProcessing $100 via PayPal#include <iostream>#include <string>
// Interface (abstract class in C++)class PaymentProcessor {public: // Pure virtual methods (abstract methods) virtual bool processPayment(double amount) = 0; virtual bool refund(const std::string& transactionId) = 0;
// Concrete method (like default method) virtual bool validateAmount(double amount) const { return amount > 0; }
virtual ~PaymentProcessor() = default;};
// Implementationclass CreditCardProcessor : public PaymentProcessor {private: std::string apiKey;
public: CreditCardProcessor(const std::string& apiKey) : apiKey(apiKey) {}
bool processPayment(double amount) override { if (!validateAmount(amount)) { return false; } std::cout << "Processing $" << amount << " via credit card" << std::endl; return true; }
bool refund(const std::string& transactionId) override { std::cout << "Refunding transaction " << transactionId << " via credit card" << std::endl; return true; }};
class PayPalProcessor : public PaymentProcessor {public: bool processPayment(double amount) override { if (!validateAmount(amount)) { return false; } std::cout << "Processing $" << amount << " via PayPal" << std::endl; return true; }
bool refund(const std::string& transactionId) override { std::cout << "Refunding transaction " << transactionId << " via PayPal" << std::endl; return true; }};
// Usage - polymorphismvoid checkout(PaymentProcessor* processor, double amount) { processor->processPayment(amount);}
int main() { CreditCardProcessor creditCard("api_key_123"); PayPalProcessor paypal;
checkout(&creditCard, 100.0); // Works checkout(&paypal, 100.0); // Works
return 0;}Processing $100 via credit cardProcessing $100 via PayPalusing System;
// Interface definitionpublic interface IPaymentProcessor{ bool ProcessPayment(double amount); bool Refund(string transactionId);}
// Abstract class for shared functionalitypublic abstract class PaymentProcessorBase : IPaymentProcessor{ public abstract bool ProcessPayment(double amount); public abstract bool Refund(string transactionId);
// Shared validation method protected bool ValidateAmount(double amount) { return amount > 0; }}
// Implementationpublic class CreditCardProcessor : PaymentProcessorBase{ private string apiKey;
public CreditCardProcessor(string apiKey) { this.apiKey = apiKey; }
public override bool ProcessPayment(double amount) { if (!ValidateAmount(amount)) { return false; } Console.WriteLine($"Processing ${amount} via credit card"); return true; }
public override bool Refund(string transactionId) { Console.WriteLine($"Refunding transaction {transactionId} via credit card"); return true; }}
public class PayPalProcessor : PaymentProcessorBase{ public override bool ProcessPayment(double amount) { if (!ValidateAmount(amount)) { return false; } Console.WriteLine($"Processing ${amount} via PayPal"); return true; }
public override bool Refund(string transactionId) { Console.WriteLine($"Refunding transaction {transactionId} via PayPal"); return true; }}
class Program{ static void Checkout(IPaymentProcessor processor, double amount) { processor.ProcessPayment(amount); }
static void Main() { IPaymentProcessor creditCard = new CreditCardProcessor("api_key_123"); IPaymentProcessor paypal = new PayPalProcessor();
Checkout(creditCard, 100.0); // Works Checkout(paypal, 100.0); // Works }}Processing $100 via credit cardProcessing $100 via PayPalpackage main
import "fmt"
type PaymentProcessor interface { ProcessPayment(amount float64) bool Refund(transactionID string) bool}
func validateAmount(amount float64) bool { return amount > 0}
type CreditCardProcessor struct { APIKey string}
func (c *CreditCardProcessor) ProcessPayment(amount float64) bool { if !validateAmount(amount) { return false } fmt.Printf("Processing $%g via credit card\n", amount) return true}
func (*CreditCardProcessor) Refund(transactionID string) bool { fmt.Printf("Refunding transaction %s via credit card\n", transactionID) return true}
type PayPalProcessor struct{}
func (*PayPalProcessor) ProcessPayment(amount float64) bool { if !validateAmount(amount) { return false } fmt.Printf("Processing $%g via PayPal\n", amount) return true}
func (*PayPalProcessor) Refund(transactionID string) bool { fmt.Printf("Refunding transaction %s via PayPal\n", transactionID) return true}
func checkout(p PaymentProcessor, amount float64) { p.ProcessPayment(amount)}
func main() { cc := &CreditCardProcessor{APIKey: "api_key_123"} pp := &PayPalProcessor{}
checkout(cc, 100.0) checkout(pp, 100.0)}Processing $100 via credit cardProcessing $100 via PayPaltrait PaymentProcessor { fn process_payment(&self, amount: f64) -> bool; fn refund(&self, transaction_id: &str) -> bool;}
fn validate_amount(amount: f64) -> bool { amount > 0.0}
struct CreditCardProcessor { api_key: String,}
impl PaymentProcessor for CreditCardProcessor { fn process_payment(&self, amount: f64) -> bool { if !validate_amount(amount) { return false; } println!("Processing ${} via credit card", amount); true }
fn refund(&self, transaction_id: &str) -> bool { println!("Refunding transaction {} via credit card", transaction_id); true }}
struct PayPalProcessor;
impl PaymentProcessor for PayPalProcessor { fn process_payment(&self, amount: f64) -> bool { if !validate_amount(amount) { return false; } println!("Processing ${} via PayPal", amount); true }
fn refund(&self, transaction_id: &str) -> bool { println!("Refunding transaction {} via PayPal", transaction_id); true }}
fn checkout(p: &dyn PaymentProcessor, amount: f64) { p.process_payment(amount);}
fn main() { let cc = CreditCardProcessor { api_key: "api_key_123".into(), }; let pp = PayPalProcessor;
checkout(&cc, 100.0); checkout(&pp, 100.0);}Processing $100 via credit cardProcessing $100 via PayPalMultiple Interface Implementation
Section titled “Multiple Interface Implementation”Classes can implement multiple interfaces:
💡 Tip: Click dropdown to switch between languages
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!"Flying through the airSwimming in waterQuack!public interface Flyable { void fly();}
public interface Swimmable { void swim();}
public class Duck implements Flyable, Swimmable { @Override public void fly() { System.out.println("Flying through the air"); }
@Override public void swim() { System.out.println("Swimming in water"); }
public void quack() { System.out.println("Quack!"); }}
// Usagepublic class Main { public static void main(String[] args) { Duck duck = new Duck(); duck.fly(); // "Flying through the air" duck.swim(); // "Swimming in water" duck.quack(); // "Quack!" }}Flying through the airSwimming in waterQuack!interface Flyable { fly(): void;}
interface Swimmable { swim(): void;}
class Duck implements Flyable, Swimmable { fly(): void { console.log("Flying through the air"); }
swim(): void { console.log("Swimming in water"); }
quack(): void { console.log("Quack!"); }}
const duck = new Duck();duck.fly(); // "Flying through the air"duck.swim(); // "Swimming in water"duck.quack(); // "Quack!"Flying through the airSwimming in waterQuack!#include <iostream>
// Abstract classes act as interfaces in C++class Flyable {public: virtual void fly() const = 0; virtual ~Flyable() = default;};
class Swimmable {public: virtual void swim() const = 0; virtual ~Swimmable() = default;};
// Duck implements multiple interfacesclass Duck : public Flyable, public Swimmable {public: void fly() const override { std::cout << "Flying through the air" << std::endl; }
void swim() const override { std::cout << "Swimming in water" << std::endl; }
void quack() const { std::cout << "Quack!" << std::endl; }};
int main() { Duck duck; duck.fly(); // "Flying through the air" duck.swim(); // "Swimming in water" duck.quack(); // "Quack!"
return 0;}Flying through the airSwimming in waterQuack!using System;
public interface IFlyable{ void Fly();}
public interface ISwimmable{ void Swim();}
public class Duck : IFlyable, ISwimmable{ public void Fly() { Console.WriteLine("Flying through the air"); }
public void Swim() { Console.WriteLine("Swimming in water"); }
public void Quack() { Console.WriteLine("Quack!"); }}
class Program{ static void Main() { Duck duck = new Duck(); duck.Fly(); // "Flying through the air" duck.Swim(); // "Swimming in water" duck.Quack(); // "Quack!" }}Flying through the airSwimming in waterQuack!package main
import "fmt"
type Flyable interface{ Fly() }type Swimmable interface{ Swim() }
type Duck struct{}
func (*Duck) Fly() { fmt.Println("Flying through the air")}
func (*Duck) Swim() { fmt.Println("Swimming in water")}
func (*Duck) Quack() { fmt.Println("Quack!")}
var ( _ Flyable = (*Duck)(nil) _ Swimmable = (*Duck)(nil))
func main() { duck := &Duck{} duck.Fly() duck.Swim() duck.Quack()}Flying through the airSwimming in waterQuack!trait Flyable { fn fly(&self);}
trait Swimmable { fn swim(&self);}
struct Duck;
impl Flyable for Duck { fn fly(&self) { println!("Flying through the air"); }}
impl Swimmable for Duck { fn swim(&self) { println!("Swimming in water"); }}
impl Duck { fn quack(&self) { println!("Quack!"); }}
fn main() { let duck = Duck; duck.fly(); duck.swim(); duck.quack();}Flying through the airSwimming in waterQuack!Real-World Example: Notification System
Section titled “Real-World Example: Notification System” 💡 Tip: Click dropdown to switch between languages
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)
# Usagemanager = NotificationManager()manager.add_service(EmailService())manager.add_service(SMSService())
manager.broadcast("+1234567890", "Your order has shipped!")Sending SMS to +1234567890: Your order has shipped!public interface NotificationService { boolean send(String recipient, String message); boolean canSend(String recipient);}
public class EmailService implements NotificationService { @Override public boolean send(String recipient, String message) { if (!canSend(recipient)) { return false; } System.out.println("Sending email to " + recipient + ": " + message); return true; }
@Override public boolean canSend(String recipient) { return recipient.contains("@"); }}
public class SMSService implements NotificationService { @Override public boolean send(String recipient, String message) { if (!canSend(recipient)) { return false; } System.out.println("Sending SMS to " + recipient + ": " + message.substring(0, Math.min(50, message.length())) + "..."); return true; }
@Override public boolean canSend(String recipient) { return recipient.startsWith("+"); }}
public class NotificationManager { private java.util.List<NotificationService> services;
public NotificationManager() { this.services = new java.util.ArrayList<>(); }
public void addService(NotificationService service) { this.services.add(service); }
public void broadcast(String recipient, String message) { for (NotificationService service : services) { if (service.canSend(recipient)) { service.send(recipient, message); } } }}
// Usagepublic class Main { public static void main(String[] args) { NotificationManager manager = new NotificationManager(); manager.addService(new EmailService()); manager.addService(new SMSService());
manager.broadcast("+1234567890", "Your order has shipped!"); }}Sending SMS to +1234567890: Your order has shipped!// Interface for notification servicesinterface NotificationService { send(recipient: string, message: string): boolean; canSend(recipient: string): boolean;}
class EmailService implements NotificationService { send(recipient: string, message: string): boolean { if (!this.canSend(recipient)) { return false; } console.log(`Sending email to ${recipient}: ${message}`); return true; }
canSend(recipient: string): boolean { return recipient.includes("@"); }}
class SMSService implements NotificationService { send(recipient: string, message: string): boolean { if (!this.canSend(recipient)) { return false; } console.log(`Sending SMS to ${recipient}: ${message.substring(0, 50)}...`); return true; }
canSend(recipient: string): boolean { return recipient.startsWith("+"); }}
class NotificationManager { private services: NotificationService[] = [];
addService(service: NotificationService): void { this.services.push(service); }
broadcast(recipient: string, message: string): void { for (const service of this.services) { if (service.canSend(recipient)) { service.send(recipient, message); } } }}
// Usageconst manager = new NotificationManager();manager.addService(new EmailService());manager.addService(new SMSService());
manager.broadcast("+1234567890", "Your order has shipped!");Sending SMS to +1234567890: Your order has shipped!#include <iostream>#include <string>#include <vector>#include <memory>
// Interface for notification servicesclass NotificationService {public: virtual bool send(const std::string& recipient, const std::string& message) = 0; virtual bool canSend(const std::string& recipient) const = 0; virtual ~NotificationService() = default;};
class EmailService : public NotificationService {public: bool send(const std::string& recipient, const std::string& message) override { if (!canSend(recipient)) { return false; } std::cout << "Sending email to " << recipient << ": " << message << std::endl; return true; }
bool canSend(const std::string& recipient) const override { return recipient.find("@") != std::string::npos; }};
class SMSService : public NotificationService {public: bool send(const std::string& recipient, const std::string& message) override { if (!canSend(recipient)) { return false; } std::string truncated = message.length() > 50 ? message.substr(0, 50) + "..." : message; std::cout << "Sending SMS to " << recipient << ": " << truncated << std::endl; return true; }
bool canSend(const std::string& recipient) const override { return recipient.rfind("+", 0) == 0; }};
class NotificationManager {private: std::vector<std::shared_ptr<NotificationService>> services;
public: void addService(std::shared_ptr<NotificationService> service) { services.push_back(service); }
void broadcast(const std::string& recipient, const std::string& message) { for (const auto& service : services) { if (service->canSend(recipient)) { service->send(recipient, message); } } }};
int main() { NotificationManager manager; manager.addService(std::make_shared<EmailService>()); manager.addService(std::make_shared<SMSService>());
manager.broadcast("+1234567890", "Your order has shipped!");
return 0;}Sending SMS to +1234567890: Your order has shipped!using System;using System.Collections.Generic;
// Interface for notification servicespublic interface INotificationService{ bool Send(string recipient, string message); bool CanSend(string recipient);}
public class EmailService : INotificationService{ public bool Send(string recipient, string message) { if (!CanSend(recipient)) { return false; } Console.WriteLine($"Sending email to {recipient}: {message}"); return true; }
public bool CanSend(string recipient) { return recipient.Contains("@"); }}
public class SMSService : INotificationService{ public bool Send(string recipient, string message) { if (!CanSend(recipient)) { return false; } string truncated = message.Length > 50 ? message.Substring(0, 50) + "..." : message; Console.WriteLine($"Sending SMS to {recipient}: {truncated}"); return true; }
public bool CanSend(string recipient) { return recipient.StartsWith("+"); }}
public class NotificationManager{ private List<INotificationService> services = new List<INotificationService>();
public void AddService(INotificationService service) { services.Add(service); }
public void Broadcast(string recipient, string message) { foreach (var service in services) { if (service.CanSend(recipient)) { service.Send(recipient, message); } } }}
class Program{ static void Main() { NotificationManager manager = new NotificationManager(); manager.AddService(new EmailService()); manager.AddService(new SMSService());
manager.Broadcast("+1234567890", "Your order has shipped!"); }}Sending SMS to +1234567890: Your order has shipped!package main
import ( "fmt" "strings")
type NotificationService interface { Send(recipient, message string) bool CanSend(recipient string) bool}
type EmailService struct{}
func (e *EmailService) Send(recipient, message string) bool { if !e.CanSend(recipient) { return false } fmt.Printf("Sending email to %s: %s\n", recipient, message) return true}
func (*EmailService) CanSend(recipient string) bool { return strings.Contains(recipient, "@")}
type SMSService struct{}
func (s *SMSService) Send(recipient, message string) bool { if !s.CanSend(recipient) { return false } if len(message) > 50 { message = message[:50] + "..." } fmt.Printf("Sending SMS to %s: %s\n", recipient, message) return true}
func (*SMSService) CanSend(recipient string) bool { return strings.HasPrefix(recipient, "+")}
type NotificationManager struct { Services []NotificationService}
func (m *NotificationManager) AddService(s NotificationService) { m.Services = append(m.Services, s)}
func (m *NotificationManager) Broadcast(recipient, message string) { for _, s := range m.Services { if s.CanSend(recipient) { s.Send(recipient, message) } }}
func main() { m := &NotificationManager{} m.AddService(&EmailService{}) m.AddService(&SMSService{})
m.Broadcast("+1234567890", "Your order has shipped!")}Sending SMS to +1234567890: Your order has shipped!trait NotificationService { fn send(&self, recipient: &str, message: &str) -> bool; fn can_send(&self, recipient: &str) -> bool;}
struct EmailService;
impl NotificationService for EmailService { fn send(&self, recipient: &str, message: &str) -> bool { if !self.can_send(recipient) { return false; } println!("Sending email to {}: {}", recipient, message); true }
fn can_send(&self, recipient: &str) -> bool { recipient.contains('@') }}
struct SmsService;
impl NotificationService for SmsService { fn send(&self, recipient: &str, message: &str) -> bool { if !self.can_send(recipient) { return false; } let message = if message.len() > 50 { format!("{}...", &message[..50]) } else { message.to_string() }; println!("Sending SMS to {}: {}", recipient, message); true }
fn can_send(&self, recipient: &str) -> bool { recipient.starts_with('+') }}
struct NotificationManager { services: Vec<Box<dyn NotificationService>>,}
impl NotificationManager { fn add_service(&mut self, service: Box<dyn NotificationService>) { self.services.push(service); }
fn broadcast(&self, recipient: &str, message: &str) { for service in &self.services { if service.can_send(recipient) { service.send(recipient, message); } } }}
fn main() { let mut manager = NotificationManager { services: vec![] }; manager.add_service(Box::new(EmailService)); manager.add_service(Box::new(SmsService));
manager.broadcast("+1234567890", "Your order has shipped!");}Sending SMS to +1234567890: Your order has shipped!Visual Representation
Section titled “Visual Representation”Key Takeaways
Section titled “Key Takeaways”When to Use Interfaces
Section titled “When to Use Interfaces”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.)