TechWayFit
● Design Principles

Interface Segregation Principle - Design Focused, Client-Specific Interfaces

Tech Buddy August 11, 2025 13 min read
Interface Segregation Principle - Design Focused, Client-Specific Interfaces

🎯 Understanding the Interface Segregation Principle

The Interface Segregation Principle (ISP) is the fourth principle in the SOLID design principles, introduced by Robert C. Martin. It states that clients should not be forced to depend on interfaces they do not use.

In simpler terms, it's better to have many small, specific interfaces than one large, general-purpose interface. This principle encourages creating focused interfaces that serve specific client needs rather than forcing clients to implement methods they don't need.

When ISP is violated, the consequences can be significant:

  • Unnecessary Dependencies: Classes are forced to implement methods they don't need, creating artificial dependencies and coupling.
  • Interface Pollution: Large interfaces become bloated with methods that only some implementations actually use, making them hard to understand and maintain.
  • Forced Implementation: Clients must provide empty or exception-throwing implementations for methods they don't use, violating the Liskov Substitution Principle.
  • Reduced Flexibility: Changes to unused methods can break client implementations that don't even use those methods.
  • Testing Complexity: Mock implementations become more complex as they need to handle more methods, even irrelevant ones.
  • Code Bloat: Classes become larger and more complex than necessary, reducing readability and maintainability.

By adhering to ISP, you create interfaces that are focused, cohesive, and easy to implement, leading to more maintainable and flexible code.

💻 Examples of ISP in Action

Let's explore how ISP can be applied in real-world scenarios using multiple programming languages. These examples demonstrate common violations and how to refactor them for better interface design.

Basic Example: Worker Interface

// ❌ Violates ISP - Forces all workers to implement all methods
                      public interface IWorker {
                          void Work();
                          void Eat();
                          void Sleep();
                          void Program();
                          void ManagePeople();
                          void Drive();
                      }
                      
                      public class Developer : IWorker {
                          public void Work() {
                              Console.WriteLine("Writing code");
                          }
                          
                          public void Eat() {
                              Console.WriteLine("Eating lunch");
                          }
                          
                          public void Sleep() {
                              Console.WriteLine("Sleeping");
                          }
                          
                          public void Program() {
                              Console.WriteLine("Programming applications");
                          }
                          
                          // ISP violation - developers don't necessarily manage people
                          public void ManagePeople() {
                              throw new NotImplementedException("Developers don't manage people");
                          }
                          
                          // ISP violation - not all developers drive
                          public void Drive() {
                              throw new NotImplementedException("Not all developers drive");
                          }
                      }
                      
                      public class Manager : IWorker {
                          public void Work() {
                              Console.WriteLine("Managing team");
                          }
                          
                          public void Eat() {
                              Console.WriteLine("Eating lunch");
                          }
                          
                          public void Sleep() {
                              Console.WriteLine("Sleeping");
                          }
                          
                          // ISP violation - managers don't necessarily program
                          public void Program() {
                              throw new NotImplementedException("Managers don't program");
                          }
                          
                          public void ManagePeople() {
                              Console.WriteLine("Managing people");
                          }
                          
                          public void Drive() {
                              Console.WriteLine("Driving to meetings");
                          }
                      }
                      
                      // ✅ Follows ISP - Segregated interfaces based on client needs
                      public interface IWorkable {
                          void Work();
                      }
                      
                      public interface IEatable {
                          void Eat();
                      }
                      
                      public interface ISleepable {
                          void Sleep();
                      }
                      
                      public interface IProgrammable {
                          void Program();
                      }
                      
                      public interface IManageable {
                          void ManagePeople();
                      }
                      
                      public interface IDriveable {
                          void Drive();
                      }
                      
                      public class Developer : IWorkable, IEatable, ISleepable, IProgrammable {
                          public void Work() {
                              Console.WriteLine("Writing code");
                          }
                          
                          public void Eat() {
                              Console.WriteLine("Eating lunch");
                          }
                          
                          public void Sleep() {
                              Console.WriteLine("Sleeping");
                          }
                          
                          public void Program() {
                              Console.WriteLine("Programming applications");
                          }
                      }
                      
                      public class Manager : IWorkable, IEatable, ISleepable, IManageable, IDriveable {
                          public void Work() {
                              Console.WriteLine("Managing team");
                          }
                          
                          public void Eat() {
                              Console.WriteLine("Eating lunch");
                          }
                          
                          public void Sleep() {
                              Console.WriteLine("Sleeping");
                          }
                          
                          public void ManagePeople() {
                              Console.WriteLine("Managing people");
                          }
                          
                          public void Drive() {
                              Console.WriteLine("Driving to meetings");
                          }
                      }
                      
                      public class SeniorDeveloper : IWorkable, IEatable, ISleepable, IProgrammable, IManageable {
                          public void Work() {
                              Console.WriteLine("Leading development and coding");
                          }
                          
                          public void Eat() {
                              Console.WriteLine("Eating lunch");
                          }
                          
                          public void Sleep() {
                              Console.WriteLine("Sleeping");
                          }
                          
                          public void Program() {
                              Console.WriteLine("Programming complex systems");
                          }
                          
                          public void ManagePeople() {
                              Console.WriteLine("Mentoring junior developers");
                          }
                      }
                        

Python Example: Document Processor

# ❌ Violates ISP - Forces all processors to implement all methods
                      from abc import ABC, abstractmethod
                      
                      class DocumentProcessor(ABC):
                          @abstractmethod
                          def read_document(self, path: str):
                              pass
                          
                          @abstractmethod
                          def write_document(self, path: str, content: str):
                              pass
                          
                          @abstractmethod
                          def encrypt_document(self, path: str):
                              pass
                          
                          @abstractmethod
                          def compress_document(self, path: str):
                              pass
                          
                          @abstractmethod
                          def email_document(self, path: str, recipient: str):
                              pass
                          
                          @abstractmethod
                          def print_document(self, path: str):
                              pass
                      
                      class SimpleTextProcessor(DocumentProcessor):
                          def read_document(self, path: str):
                              print(f"Reading text file: {path}")
                          
                          def write_document(self, path: str, content: str):
                              print(f"Writing text to: {path}")
                          
                          # ISP violation - simple text processor doesn't need encryption
                          def encrypt_document(self, path: str):
                              raise NotImplementedError("Text processor doesn't support encryption")
                          
                          # ISP violation - simple text processor doesn't need compression
                          def compress_document(self, path: str):
                              raise NotImplementedError("Text processor doesn't support compression")
                          
                          # ISP violation - simple text processor doesn't email
                          def email_document(self, path: str, recipient: str):
                              raise NotImplementedError("Text processor doesn't support emailing")
                          
                          # ISP violation - simple text processor doesn't print
                          def print_document(self, path: str):
                              raise NotImplementedError("Text processor doesn't support printing")
                      
                      # ✅ Follows ISP - Segregated interfaces based on capabilities
                      class DocumentReader(ABC):
                          @abstractmethod
                          def read_document(self, path: str):
                              pass
                      
                      class DocumentWriter(ABC):
                          @abstractmethod
                          def write_document(self, path: str, content: str):
                              pass
                      
                      class DocumentEncryptor(ABC):
                          @abstractmethod
                          def encrypt_document(self, path: str):
                              pass
                      
                      class DocumentCompressor(ABC):
                          @abstractmethod
                          def compress_document(self, path: str):
                              pass
                      
                      class DocumentEmailer(ABC):
                          @abstractmethod
                          def email_document(self, path: str, recipient: str):
                              pass
                      
                      class DocumentPrinter(ABC):
                          @abstractmethod
                          def print_document(self, path: str):
                              pass
                      
                      class SimpleTextProcessor(DocumentReader, DocumentWriter):
                          def read_document(self, path: str):
                              print(f"Reading text file: {path}")
                              return "text content"
                          
                          def write_document(self, path: str, content: str):
                              print(f"Writing text to: {path}")
                      
                      class SecureDocumentProcessor(DocumentReader, DocumentWriter, DocumentEncryptor):
                          def read_document(self, path: str):
                              print(f"Reading secure document: {path}")
                              return "encrypted content"
                          
                          def write_document(self, path: str, content: str):
                              print(f"Writing secure document to: {path}")
                          
                          def encrypt_document(self, path: str):
                              print(f"Encrypting document: {path}")
                      
                      class FullFeaturedProcessor(DocumentReader, DocumentWriter, DocumentEncryptor, 
                                                DocumentCompressor, DocumentEmailer, DocumentPrinter):
                          def read_document(self, path: str):
                              print(f"Reading document: {path}")
                              return "document content"
                          
                          def write_document(self, path: str, content: str):
                              print(f"Writing document to: {path}")
                          
                          def encrypt_document(self, path: str):
                              print(f"Encrypting document: {path}")
                          
                          def compress_document(self, path: str):
                              print(f"Compressing document: {path}")
                          
                          def email_document(self, path: str, recipient: str):
                              print(f"Emailing document {path} to {recipient}")
                          
                          def print_document(self, path: str):
                              print(f"Printing document: {path}")
                      
                      # Usage with proper segregation
                      def process_documents():
                          # Only use what you need
                          simple_processor = SimpleTextProcessor()
                          secure_processor = SecureDocumentProcessor()
                          full_processor = FullFeaturedProcessor()
                          
                          # Each processor only implements what it actually supports
                          readers = [simple_processor, secure_processor, full_processor]
                          for reader in readers:
                              content = reader.read_document("document.txt")
                          
                          # Only secure and full processors can encrypt
                          encryptors = [secure_processor, full_processor]
                          for encryptor in encryptors:
                              encryptor.encrypt_document("document.txt")
                          
                          # Only full processor can email
                          if isinstance(full_processor, DocumentEmailer):
                              full_processor.email_document("document.txt", "user@example.com")
                        

JavaScript Example: Media Player

// ❌ Violates ISP - Forces all players to implement all methods
                      class MediaPlayer {
                          play() {
                              throw new Error('Method must be implemented');
                          }
                          
                          pause() {
                              throw new Error('Method must be implemented');
                          }
                          
                          stop() {
                              throw new Error('Method must be implemented');
                          }
                          
                          seek(position) {
                              throw new Error('Method must be implemented');
                          }
                          
                          setVolume(volume) {
                              throw new Error('Method must be implemented');
                          }
                          
                          showSubtitles() {
                              throw new Error('Method must be implemented');
                          }
                          
                          changeVideoQuality(quality) {
                              throw new Error('Method must be implemented');
                          }
                          
                          recordStream() {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class AudioPlayer extends MediaPlayer {
                          play() {
                              console.log('Playing audio');
                          }
                          
                          pause() {
                              console.log('Pausing audio');
                          }
                          
                          stop() {
                              console.log('Stopping audio');
                          }
                          
                          seek(position) {
                              console.log(`Seeking to ${position}`);
                          }
                          
                          setVolume(volume) {
                              console.log(`Setting volume to ${volume}`);
                          }
                          
                          // ISP violation - audio doesn't have subtitles
                          showSubtitles() {
                              throw new Error('Audio players do not support subtitles');
                          }
                          
                          // ISP violation - audio doesn't have video quality
                          changeVideoQuality(quality) {
                              throw new Error('Audio players do not have video quality');
                          }
                          
                          // ISP violation - not all audio players can record
                          recordStream() {
                              throw new Error('This audio player cannot record');
                          }
                      }
                      
                      // ✅ Follows ISP - Segregated interfaces based on capabilities
                      class Playable {
                          play() {
                              throw new Error('Method must be implemented');
                          }
                          
                          stop() {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class Pausable {
                          pause() {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class Seekable {
                          seek(position) {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class VolumeControllable {
                          setVolume(volume) {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class SubtitleCapable {
                          showSubtitles() {
                              throw new Error('Method must be implemented');
                          }
                          
                          hideSubtitles() {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class VideoQualityControllable {
                          changeVideoQuality(quality) {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      class Recordable {
                          startRecording() {
                              throw new Error('Method must be implemented');
                          }
                          
                          stopRecording() {
                              throw new Error('Method must be implemented');
                          }
                      }
                      
                      // Mixin function to combine multiple interfaces
                      function mixinInterfaces(baseClass, ...mixins) {
                          mixins.forEach(mixin => {
                              Object.getOwnPropertyNames(mixin.prototype).forEach(name => {
                                  if (name !== 'constructor') {
                                      baseClass.prototype[name] = mixin.prototype[name];
                                  }
                              });
                          });
                      }
                      
                      class AudioPlayer extends Playable {
                          constructor() {
                              super();
                              mixinInterfaces(this.constructor, Pausable, Seekable, VolumeControllable);
                          }
                          
                          play() {
                              console.log('Playing audio');
                          }
                          
                          stop() {
                              console.log('Stopping audio');
                          }
                          
                          pause() {
                              console.log('Pausing audio');
                          }
                          
                          seek(position) {
                              console.log(`Seeking audio to ${position}`);
                          }
                          
                          setVolume(volume) {
                              console.log(`Setting audio volume to ${volume}`);
                          }
                      }
                      
                      class VideoPlayer extends Playable {
                          constructor() {
                              super();
                              mixinInterfaces(this.constructor, Pausable, Seekable, VolumeControllable, 
                                             SubtitleCapable, VideoQualityControllable);
                          }
                          
                          play() {
                              console.log('Playing video');
                          }
                          
                          stop() {
                              console.log('Stopping video');
                          }
                          
                          pause() {
                              console.log('Pausing video');
                          }
                          
                          seek(position) {
                              console.log(`Seeking video to ${position}`);
                          }
                          
                          setVolume(volume) {
                              console.log(`Setting video volume to ${volume}`);
                          }
                          
                          showSubtitles() {
                              console.log('Showing subtitles');
                          }
                          
                          hideSubtitles() {
                              console.log('Hiding subtitles');
                          }
                          
                          changeVideoQuality(quality) {
                              console.log(`Changing video quality to ${quality}`);
                          }
                      }
                      
                      class LiveStreamPlayer extends Playable {
                          constructor() {
                              super();
                              mixinInterfaces(this.constructor, VolumeControllable, Recordable);
                          }
                          
                          play() {
                              console.log('Starting live stream');
                          }
                          
                          stop() {
                              console.log('Stopping live stream');
                          }
                          
                          setVolume(volume) {
                              console.log(`Setting stream volume to ${volume}`);
                          }
                          
                          startRecording() {
                              console.log('Starting stream recording');
                          }
                          
                          stopRecording() {
                              console.log('Stopping stream recording');
                          }
                      }
                      
                      // Usage with proper interface segregation
                      const audioPlayer = new AudioPlayer();
                      const videoPlayer = new VideoPlayer();
                      const livePlayer = new LiveStreamPlayer();
                      
                      // All players can play and stop
                      [audioPlayer, videoPlayer, livePlayer].forEach(player => {
                          player.play();
                          player.stop();
                      });
                      
                      // Only video and live players can control volume
                      [audioPlayer, videoPlayer].forEach(player => {
                          if (typeof player.setVolume === 'function') {
                              player.setVolume(80);
                          }
                      });
                      
                      // Only video player has subtitles
                      if (typeof videoPlayer.showSubtitles === 'function') {
                          videoPlayer.showSubtitles();
                      }
                      
                      // Only live player can record
                      if (typeof livePlayer.startRecording === 'function') {
                          livePlayer.startRecording();
                      }
                        

🌍 Real-World ISP Examples

Let's examine complex, real-world scenarios where ISP compliance is crucial for maintainable and flexible software systems.

Example 1: E-commerce Order Processing

// ❌ Violates ISP - Forces all processors to implement all methods
                      public interface IOrderProcessor {
                          void ValidateOrder(Order order);
                          void CalculateTax(Order order);
                          void CalculateShipping(Order order);
                          void ProcessPayment(Order order);
                          void ApplyDiscount(Order order);
                          void UpdateInventory(Order order);
                          void SendConfirmationEmail(Order order);
                          void GenerateInvoice(Order order);
                          void ScheduleShipping(Order order);
                          void HandleRefund(Order order);
                          void ProcessSubscription(Order order);
                          void HandleDigitalDelivery(Order order);
                      }
                      
                      public class SimpleOrderProcessor : IOrderProcessor {
                          public void ValidateOrder(Order order) {
                              Console.WriteLine("Validating order");
                          }
                          
                          public void CalculateTax(Order order) {
                              Console.WriteLine("Calculating tax");
                          }
                          
                          public void CalculateShipping(Order order) {
                              Console.WriteLine("Calculating shipping");
                          }
                          
                          public void ProcessPayment(Order order) {
                              Console.WriteLine("Processing payment");
                          }
                          
                          // ISP violations - simple processor doesn't handle these
                          public void ApplyDiscount(Order order) {
                              throw new NotImplementedException("Simple processor doesn't handle discounts");
                          }
                          
                          public void UpdateInventory(Order order) {
                              throw new NotImplementedException("Simple processor doesn't update inventory");
                          }
                          
                          public void SendConfirmationEmail(Order order) {
                              throw new NotImplementedException("Simple processor doesn't send emails");
                          }
                          
                          public void GenerateInvoice(Order order) {
                              throw new NotImplementedException("Simple processor doesn't generate invoices");
                          }
                          
                          public void ScheduleShipping(Order order) {
                              throw new NotImplementedException("Simple processor doesn't schedule shipping");
                          }
                          
                          public void HandleRefund(Order order) {
                              throw new NotImplementedException("Simple processor doesn't handle refunds");
                          }
                          
                          public void ProcessSubscription(Order order) {
                              throw new NotImplementedException("Simple processor doesn't handle subscriptions");
                          }
                          
                          public void HandleDigitalDelivery(Order order) {
                              throw new NotImplementedException("Simple processor doesn't handle digital delivery");
                          }
                      }
                      
                      // ✅ Follows ISP - Segregated interfaces based on responsibilities
                      public interface IOrderValidator {
                          void ValidateOrder(Order order);
                      }
                      
                      public interface ITaxCalculator {
                          void CalculateTax(Order order);
                      }
                      
                      public interface IShippingCalculator {
                          void CalculateShipping(Order order);
                      }
                      
                      public interface IPaymentProcessor {
                          void ProcessPayment(Order order);
                      }
                      
                      public interface IDiscountApplicator {
                          void ApplyDiscount(Order order);
                      }
                      
                      public interface IInventoryManager {
                          void UpdateInventory(Order order);
                      }
                      
                      public interface INotificationSender {
                          void SendConfirmationEmail(Order order);
                      }
                      
                      public interface IInvoiceGenerator {
                          void GenerateInvoice(Order order);
                      }
                      
                      public interface IShippingScheduler {
                          void ScheduleShipping(Order order);
                      }
                      
                      public interface IRefundProcessor {
                          void HandleRefund(Order order);
                      }
                      
                      public interface ISubscriptionProcessor {
                          void ProcessSubscription(Order order);
                      }
                      
                      public interface IDigitalDeliveryHandler {
                          void HandleDigitalDelivery(Order order);
                      }
                      
                      public class SimpleOrderProcessor : IOrderValidator, ITaxCalculator, 
                                                         IShippingCalculator, IPaymentProcessor {
                          public void ValidateOrder(Order order) {
                              Console.WriteLine("Validating simple order");
                          }
                          
                          public void CalculateTax(Order order) {
                              Console.WriteLine("Calculating tax for simple order");
                          }
                          
                          public void CalculateShipping(Order order) {
                              Console.WriteLine("Calculating shipping for simple order");
                          }
                          
                          public void ProcessPayment(Order order) {
                              Console.WriteLine("Processing payment for simple order");
                          }
                      }
                      
                      public class EnterpriseOrderProcessor : IOrderValidator, ITaxCalculator, IShippingCalculator,
                                                             IPaymentProcessor, IDiscountApplicator, IInventoryManager,
                                                             INotificationSender, IInvoiceGenerator, IShippingScheduler {
                          public void ValidateOrder(Order order) {
                              Console.WriteLine("Validating enterprise order with advanced rules");
                          }
                          
                          public void CalculateTax(Order order) {
                              Console.WriteLine("Calculating tax with complex tax rules");
                          }
                          
                          public void CalculateShipping(Order order) {
                              Console.WriteLine("Calculating shipping with multiple carriers");
                          }
                          
                          public void ProcessPayment(Order order) {
                              Console.WriteLine("Processing payment with multiple gateways");
                          }
                          
                          public void ApplyDiscount(Order order) {
                              Console.WriteLine("Applying enterprise discounts");
                          }
                          
                          public void UpdateInventory(Order order) {
                              Console.WriteLine("Updating inventory across warehouses");
                          }
                          
                          public void SendConfirmationEmail(Order order) {
                              Console.WriteLine("Sending detailed confirmation email");
                          }
                          
                          public void GenerateInvoice(Order order) {
                              Console.WriteLine("Generating detailed invoice");
                          }
                          
                          public void ScheduleShipping(Order order) {
                              Console.WriteLine("Scheduling shipping with preferred carriers");
                          }
                      }
                      
                      public class SubscriptionOrderProcessor : IOrderValidator, IPaymentProcessor, 
                                                               ISubscriptionProcessor, INotificationSender {
                          public void ValidateOrder(Order order) {
                              Console.WriteLine("Validating subscription order");
                          }
                          
                          public void ProcessPayment(Order order) {
                              Console.WriteLine("Processing recurring payment");
                          }
                          
                          public void ProcessSubscription(Order order) {
                              Console.WriteLine("Setting up subscription billing cycle");
                          }
                          
                          public void SendConfirmationEmail(Order order) {
                              Console.WriteLine("Sending subscription welcome email");
                          }
                      }
                      
                      public class DigitalOrderProcessor : IOrderValidator, IPaymentProcessor, 
                                                          IDigitalDeliveryHandler, INotificationSender {
                          public void ValidateOrder(Order order) {
                              Console.WriteLine("Validating digital product order");
                          }
                          
                          public void ProcessPayment(Order order) {
                              Console.WriteLine("Processing payment for digital product");
                          }
                          
                          public void HandleDigitalDelivery(Order order) {
                              Console.WriteLine("Delivering digital product instantly");
                          }
                          
                          public void SendConfirmationEmail(Order order) {
                              Console.WriteLine("Sending download links via email");
                          }
                      }
                      
                      // Usage with proper interface segregation
                      public class OrderProcessingService {
                          public void ProcessOrder(Order order) {
                              IOrderValidator validator = GetValidator(order.Type);
                              validator.ValidateOrder(order);
                              
                              IPaymentProcessor paymentProcessor = GetPaymentProcessor(order.Type);
                              paymentProcessor.ProcessPayment(order);
                              
                              // Only apply tax calculation for physical products
                              if (order.RequiresTaxCalculation && GetProcessor(order.Type) is ITaxCalculator taxCalculator) {
                                  taxCalculator.CalculateTax(order);
                              }
                              
                              // Only handle shipping for physical products
                              if (order.RequiresShipping && GetProcessor(order.Type) is IShippingCalculator shippingCalculator) {
                                  shippingCalculator.CalculateShipping(order);
                              }
                              
                              // Handle digital delivery for digital products
                              if (order.IsDigital && GetProcessor(order.Type) is IDigitalDeliveryHandler digitalHandler) {
                                  digitalHandler.HandleDigitalDelivery(order);
                              }
                              
                              // Send notifications if processor supports it
                              if (GetProcessor(order.Type) is INotificationSender notificationSender) {
                                  notificationSender.SendConfirmationEmail(order);
                              }
                          }
                          
                          private object GetProcessor(OrderType type) {
                              return type switch {
                                  OrderType.Simple => new SimpleOrderProcessor(),
                                  OrderType.Enterprise => new EnterpriseOrderProcessor(),
                                  OrderType.Subscription => new SubscriptionOrderProcessor(),
                                  OrderType.Digital => new DigitalOrderProcessor(),
                                  _ => throw new ArgumentException("Unknown order type")
                              };
                          }
                          
                          private IOrderValidator GetValidator(OrderType type) => (IOrderValidator)GetProcessor(type);
                          private IPaymentProcessor GetPaymentProcessor(OrderType type) => (IPaymentProcessor)GetProcessor(type);
                      }
                        

Benefits of ISP-Compliant Design

  • Focused Interfaces: Each interface has a single, well-defined purpose, making them easier to understand and implement.
  • Reduced Dependencies: Clients only depend on the methods they actually use, reducing coupling and making changes safer.
  • Better Testability: Smaller interfaces are easier to mock and test, leading to more focused unit tests.
  • Improved Flexibility: New implementations can choose which capabilities to support without being forced to implement irrelevant methods.
  • Enhanced Maintainability: Changes to one interface don't affect clients that don't use that interface.
  • Clear Contracts: Interface segregation makes the contracts between components more explicit and easier to reason about.

🎯 ISP Implementation Guidelines

Here are key guidelines and patterns for implementing the Interface Segregation Principle effectively in your code.

1. Role-Based Interface Design

Design interfaces around the roles and responsibilities that clients actually need.

// ✅ Good: Role-based interface segregation
                      public interface Readable {
                          String read();
                      }
                      
                      public interface Writable {
                          void write(String content);
                      }
                      
                      public interface Searchable {
                          List search(String query);
                      }
                      
                      public interface Cacheable {
                          void cache(String key, Object value);
                          Object getFromCache(String key);
                      }
                      
                      // Different implementations can choose their capabilities
                      public class FileDataSource implements Readable, Writable {
                          @Override
                          public String read() {
                              return "File content";
                          }
                          
                          @Override
                          public void write(String content) {
                              System.out.println("Writing to file: " + content);
                          }
                      }
                      
                      public class DatabaseDataSource implements Readable, Writable, Searchable, Cacheable {
                          private Map cache = new HashMap<>();
                          
                          @Override
                          public String read() {
                              return "Database content";
                          }
                          
                          @Override
                          public void write(String content) {
                              System.out.println("Writing to database: " + content);
                          }
                          
                          @Override
                          public List search(String query) {
                              return Arrays.asList("Search result 1", "Search result 2");
                          }
                          
                          @Override
                          public void cache(String key, Object value) {
                              cache.put(key, value);
                          }
                          
                          @Override
                          public Object getFromCache(String key) {
                              return cache.get(key);
                          }
                      }
                      
                      public class ReadOnlyApiSource implements Readable, Searchable {
                          @Override
                          public String read() {
                              return "API response";
                          }
                          
                          @Override
                          public List search(String query) {
                              return Arrays.asList("API search result");
                          }
                      }
                      
                      // Client code uses only what it needs
                      public class DataProcessor {
                          public void processReadableData(Readable dataSource) {
                              String data = dataSource.read();
                              System.out.println("Processing: " + data);
                          }
                          
                          public void searchData(Searchable dataSource, String query) {
                              List results = dataSource.search(query);
                              results.forEach(System.out::println);
                          }
                          
                          public void cacheData(Cacheable dataSource, String key, Object value) {
                              dataSource.cache(key, value);
                          }
                      }
                        

2. Capability-Based Segregation

Group methods by capabilities rather than by objects or domains.

# ✅ Good: Capability-based interface design
                      from abc import ABC, abstractmethod
                      from typing import List, Optional
                      
                      class Authenticatable(ABC):
                          @abstractmethod
                          def authenticate(self, username: str, password: str) -> bool:
                              pass
                      
                      class Authorizable(ABC):
                          @abstractmethod
                          def has_permission(self, user_id: str, permission: str) -> bool:
                              pass
                      
                      class Auditable(ABC):
                          @abstractmethod
                          def log_action(self, user_id: str, action: str, timestamp: str):
                              pass
                      
                      class Cacheable(ABC):
                          @abstractmethod
                          def get_from_cache(self, key: str) -> Optional[str]:
                              pass
                          
                          @abstractmethod
                          def put_in_cache(self, key: str, value: str):
                              pass
                      
                      class Configurable(ABC):
                          @abstractmethod
                          def get_config(self, key: str) -> str:
                              pass
                          
                          @abstractmethod
                          def set_config(self, key: str, value: str):
                              pass
                      
                      # Different service implementations choose their capabilities
                      class BasicUserService(Authenticatable):
                          def authenticate(self, username: str, password: str) -> bool:
                              print(f"Authenticating user: {username}")
                              return username == "admin" and password == "password"
                      
                      class EnterpriseUserService(Authenticatable, Authorizable, Auditable, Cacheable):
                          def __init__(self):
                              self.cache = {}
                              self.audit_log = []
                          
                          def authenticate(self, username: str, password: str) -> bool:
                              result = username == "admin" and password == "password"
                              self.log_action(username, "authenticate", "2025-08-10T10:00:00Z")
                              return result
                          
                          def has_permission(self, user_id: str, permission: str) -> bool:
                              self.log_action(user_id, f"check_permission:{permission}", "2025-08-10T10:00:00Z")
                              return True  # Simplified logic
                          
                          def log_action(self, user_id: str, action: str, timestamp: str):
                              self.audit_log.append(f"{timestamp} - {user_id}: {action}")
                              print(f"Audit: {timestamp} - {user_id}: {action}")
                          
                          def get_from_cache(self, key: str) -> Optional[str]:
                              return self.cache.get(key)
                          
                          def put_in_cache(self, key: str, value: str):
                              self.cache[key] = value
                      
                      class ConfigurableUserService(Authenticatable, Configurable):
                          def __init__(self):
                              self.config = {}
                          
                          def authenticate(self, username: str, password: str) -> bool:
                              min_password_length = int(self.get_config("min_password_length") or "8")
                              if len(password) < min_password_length:
                                  return False
                              return username == "admin" and password == "password"
                          
                          def get_config(self, key: str) -> str:
                              return self.config.get(key, "")
                          
                          def set_config(self, key: str, value: str):
                              self.config[key] = value
                              print(f"Config set: {key} = {value}")
                      
                      # Client code uses only required capabilities
                      class AuthenticationController:
                          def __init__(self, auth_service: Authenticatable):
                              self.auth_service = auth_service
                          
                          def login(self, username: str, password: str) -> bool:
                              return self.auth_service.authenticate(username, password)
                      
                      class AuditController:
                          def __init__(self, audit_service: Auditable):
                              self.audit_service = audit_service
                          
                          def log_user_action(self, user_id: str, action: str):
                              self.audit_service.log_action(user_id, action, "2025-08-10T10:00:00Z")
                      
                      class CacheController:
                          def __init__(self, cache_service: Cacheable):
                              self.cache_service = cache_service
                          
                          def get_cached_data(self, key: str) -> Optional[str]:
                              return self.cache_service.get_from_cache(key)
                          
                          def cache_data(self, key: str, value: str):
                              self.cache_service.put_in_cache(key, value)
                      
                      # Usage
                      basic_service = BasicUserService()
                      enterprise_service = EnterpriseUserService()
                      configurable_service = ConfigurableUserService()
                      
                      # Each controller only depends on what it needs
                      auth_controller = AuthenticationController(basic_service)  # Can use any Authenticatable
                      audit_controller = AuditController(enterprise_service)     # Needs Auditable
                      cache_controller = CacheController(enterprise_service)     # Needs Cacheable
                      
                      # This promotes flexibility and testability
                      auth_controller.login("admin", "password")
                      audit_controller.log_user_action("user123", "login")
                      cache_controller.cache_data("user_session", "abc123")
                        

3. Progressive Interface Composition

Build complex interfaces by composing simpler ones, allowing clients to implement only what they need.

// ✅ Good: Progressive interface composition
                      interface Readable {
                          read(): string;
                      }
                      
                      interface Writable {
                          write(content: string): void;
                      }
                      
                      interface Seekable {
                          seek(position: number): void;
                          getPosition(): number;
                      }
                      
                      interface Lockable {
                          lock(): void;
                          unlock(): void;
                          isLocked(): boolean;
                      }
                      
                      interface Compressible {
                          compress(): void;
                          decompress(): void;
                      }
                      
                      interface Encryptable {
                          encrypt(key: string): void;
                          decrypt(key: string): void;
                      }
                      
                      // Progressive composition - clients implement what they support
                      interface BasicFile extends Readable, Writable {}
                      
                      interface AdvancedFile extends BasicFile, Seekable {}
                      
                      interface SecureFile extends AdvancedFile, Lockable, Encryptable {}
                      
                      interface ArchiveFile extends SecureFile, Compressible {}
                      
                      // Implementations choose their level of functionality
                      class SimpleTextFile implements BasicFile {
                          private content: string = "";
                          
                          read(): string {
                              return this.content;
                          }
                          
                          write(content: string): void {
                              this.content = content;
                          }
                      }
                      
                      class BinaryFile implements AdvancedFile {
                          private content: string = "";
                          private position: number = 0;
                          
                          read(): string {
                              return this.content.substring(this.position);
                          }
                          
                          write(content: string): void {
                              this.content = content;
                          }
                          
                          seek(position: number): void {
                              this.position = position;
                          }
                          
                          getPosition(): number {
                              return this.position;
                          }
                      }
                      
                      class EncryptedFile implements SecureFile {
                          private content: string = "";
                          private position: number = 0;
                          private locked: boolean = false;
                          private encrypted: boolean = false;
                          
                          read(): string {
                              if (this.locked) {
                                  throw new Error("File is locked");
                              }
                              if (this.encrypted) {
                                  throw new Error("File is encrypted");
                              }
                              return this.content.substring(this.position);
                          }
                          
                          write(content: string): void {
                              if (this.locked) {
                                  throw new Error("File is locked");
                              }
                              this.content = content;
                          }
                          
                          seek(position: number): void {
                              this.position = position;
                          }
                          
                          getPosition(): number {
                              return this.position;
                          }
                          
                          lock(): void {
                              this.locked = true;
                          }
                          
                          unlock(): void {
                              this.locked = false;
                          }
                          
                          isLocked(): boolean {
                              return this.locked;
                          }
                          
                          encrypt(key: string): void {
                              this.encrypted = true;
                              console.log(`File encrypted with key: ${key}`);
                          }
                          
                          decrypt(key: string): void {
                              this.encrypted = false;
                              console.log(`File decrypted with key: ${key}`);
                          }
                      }
                      
                      // Client functions work with appropriate interface levels
                      function readFile(file: Readable): string {
                          return file.read();
                      }
                      
                      function writeFile(file: Writable, content: string): void {
                          file.write(content);
                      }
                      
                      function seekInFile(file: Seekable, position: number): void {
                          file.seek(position);
                      }
                      
                      function secureFile(file: Lockable & Encryptable, key: string): void {
                          file.lock();
                          file.encrypt(key);
                      }
                      
                      // Usage demonstrates flexibility
                      const simpleFile = new SimpleTextFile();
                      const binaryFile = new BinaryFile();
                      const encryptedFile = new EncryptedFile();
                      
                      // All files can be read
                      [simpleFile, binaryFile, encryptedFile].forEach(file => {
                          console.log(readFile(file));
                      });
                      
                      // Only advanced and secure files can seek
                      [binaryFile, encryptedFile].forEach(file => {
                          seekInFile(file, 10);
                      });
                      
                      // Only secure files can be locked and encrypted
                      secureFile(encryptedFile, "secret-key");
                        

Key ISP Guidelines Summary

  • Keep Interfaces Small and Focused: Each interface should have a single, well-defined responsibility.
  • Design for Client Needs: Create interfaces based on what clients actually need, not what objects can do.
  • Use Composition Over Large Interfaces: Combine small interfaces rather than creating large, monolithic ones.
  • Avoid Fat Interfaces: If an interface has many methods, consider breaking it into smaller, more focused interfaces.
  • Think About Capabilities: Group methods by what they enable clients to do, not by object relationships.
  • Consider Optional Dependencies: Use interface segregation to make some dependencies optional.
  • Review Interface Usage: Regularly review which methods clients actually use and segregate accordingly.

Comments

Loading comments…

Leave a comment