Ответ
Несколько реализаций интерфейса позволяют применять принципы полиморфизма и инверсии зависимостей (DIP), что делает систему гибкой, расширяемой и легко тестируемой.
Основные практические причины:
- Разные стратегии поведения (паттерн Strategy)
interface CompressionStrategy { byte[] compress(byte[] data); }
class ZipCompression implements CompressionStrategy { / ... / } class GzipCompression implements CompressionStrategy { / ... / }
// Клиентский код зависит от абстракции, а не от конкретной реализации CompressionStrategy compressor = new ZipCompression(); byte[] result = compressor.compress(data);
2. **Подмена реализации для тестирования (Mocking)**
- Замена реального репозитория базы данных на `InMemoryRepository` в юнит-тестах.
- Использование заглушек (`Stub`) для внешних API.
3. **Адаптация к разным внешним системам**
- Один интерфейс `PaymentGateway`, но реализации для Stripe, PayPal, и т.д.
- Единый интерфейс `Logger` с реализациями для консоли, файла, Sentry, ELK.
4. **Соблюдение Open/Closed Principle**
- Новая функциональность добавляется через новые классы, а не модификацию существующего кода.
**Пример с логгером:**
```java
interface Logger {
void log(String message, LogLevel level);
}
class ConsoleLogger implements Logger {
public void log(String message, LogLevel level) {
System.out.printf("[%s] %sn", level, message);
}
}
class FileLogger implements Logger {
private Path logFile;
public void log(String message, LogLevel level) {
// Запись в файл с ротацией
}
}
// Внедрение зависимости через конструктор
class OrderService {
private final Logger logger;
public OrderService(Logger logger) { this.logger = logger; }
// ...
}
Итог: несколько реализаций интерфейса — основа для слабой связанности, лёгкого тестирования и поддержки различных вариантов поведения.