DEV Community

Hunor Vadasz-Perhat
Hunor Vadasz-Perhat

Posted on

java-core-001: programming-to-an-interface

Programming to an interface instead of a class is considered a best practice because it promotes flexibility, scalability, and adherence to key principles of object-oriented programming (OOP). Here's why:

1. Encourages Abstraction

  • Interfaces define contracts: An interface specifies what a class should do, not how it should do it. This abstraction decouples the client code (which depends on the interface) from the concrete implementation.
  • By programming to an interface, you focus on defining behaviors rather than specific implementations.

2. Supports Dependency Inversion (SOLID Principles)

  • Dependency Inversion Principle (DIP): High-level modules (business logic) should not depend on low-level modules (implementations); both should depend on abstractions (interfaces).
  • Example: A PaymentProcessor service can depend on a PaymentGateway interface rather than a specific implementation like StripeGateway or PayPalGateway. This ensures flexibility and reduces coupling.

3. Enables Polymorphism

  • By programming to interfaces, multiple classes can implement the same interface, making it easy to use them interchangeably.
  • Example: Both ArrayList and LinkedList implement the List interface. If your code depends on List rather than a specific implementation, you can swap between ArrayList and LinkedList without modifying the code.

4. Improves Code Flexibility and Reusability

  • Easier substitution: You can replace one implementation with another (e.g., switching from one database service to another) without changing client code.
  • Reusability: Code written for the interface works seamlessly with any class implementing it.

5. Facilitates Testing and Mocking

  • Mocking for tests: Interfaces allow the creation of mock implementations for unit testing.
  • Example: If you depend on a DatabaseService interface, you can test with a mock implementation instead of the actual database.

6. Future-Proofing

  • Adding new implementations is simpler because you don’t need to modify existing code. Instead, you just create a new class that implements the existing interface.

Example

// Interface
public interface Animal {
    void speak();
}

// Implementation 1
public class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("Woof!");
    }
}

// Implementation 2
public class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("Meow!");
    }
}

// Client code
public class AnimalSound {
    public void makeAnimalSpeak(Animal animal) {
        animal.speak();
    }
}
Enter fullscreen mode Exit fullscreen mode
  • By programming to the Animal interface, the AnimalSound class can work with any Animal implementation (Dog, Cat, etc.) without modification.

Key Benefits Recap:

  • Decouples code (reduces tight coupling).
  • Makes code easier to extend and maintain.
  • Simplifies testing.
  • Encourages adherence to OOP principles like abstraction and polymorphism.

By programming to interfaces, you build systems that are flexible, modular, and more aligned with best practices.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more