Real World Example

Swappable Payment Gateways

An Indian e-commerce backend may switch between Razorpay, PayU or a test gateway. The order service depends only on a PaymentGateway interface, so the gateway can be swapped through configuration, and tests use a fake one.

Example

public class Main {
    public static void main(String[] args) {
        OrderService live = new OrderService(new RazorpayGateway());
        OrderService test = new OrderService(new FakeGateway());
        live.placeOrder("ORD-501", 2499);
        test.placeOrder("ORD-502", 999);
    }
}

interface PaymentGateway {
    String charge(String orderId, long amountInPaise);

    default boolean supportsRefund() { return true; }
}

class RazorpayGateway implements PaymentGateway {
    public String charge(String orderId, long amountInPaise) {
        return "rzp_txn_" + orderId.substring(4) + " charged " + amountInPaise + " paise";
    }
}

class FakeGateway implements PaymentGateway {
    public String charge(String orderId, long amountInPaise) {
        return "FAKE-OK for " + orderId;
    }
    @Override public boolean supportsRefund() { return false; }
}

class OrderService {
    private final PaymentGateway gateway;          // depends on the interface only

    OrderService(PaymentGateway gateway) {
        this.gateway = gateway;
    }

    void placeOrder(String orderId, long rupees) {
        String result = gateway.charge(orderId, rupees * 100);
        System.out.println(result + " | refunds: " + gateway.supportsRefund());
    }
}

Output

rzp_txn_501 charged 249900 paise | refunds: true
FAKE-OK for ORD-502 | refunds: false

Note: This is exactly how Spring dependency injection works: you inject an interface, and Spring supplies the implementation.