← Назад к вопросам
Что такое Low coupling?
2.0 Middle🔥 141 комментариев
#SOLID и паттерны проектирования#Spring Boot и Spring Data
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Low coupling
Low coupling (слабая связанность) — это принцип архитектуры ПО, который заключается в том, что модули, классы и компоненты должны быть максимально независимы друг от друга. Это означает, что изменение в одном компоненте должно минимально влиять на другие компоненты. Low coupling часто сочетается с high cohesion (высокой связностью) в рамках самого модуля.
Противоположность: High Coupling (плохо)
// ❌ ПЛОХО: High coupling — сильная зависимость
@Controller
public class OrderController {
// Прямая зависимость от конкретного класса
private MySQLDatabase database = new MySQLDatabase();
private EmailService emailService = new GmailEmailService();
private PaymentProcessor processor = new StripePaymentProcessor();
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// Если изменится реализация database, нужно менять этот класс
Order order = database.save(new Order(request));
// Если заменим Gmail на SendGrid, нужно менять этот класс
emailService.sendConfirmation(request.getEmail());
// Если переключимся на PayPal, нужно менять этот класс
processor.charge(request.getAmount());
return order;
}
}
// Проблемы:
// 1. Сложно тестировать (невозможно подменить зависимости)
// 2. Сложно менять реализацию
// 3. Класс зависит от деталей реализации, а не интерфейсов
// 4. Нарушается SOLID принцип (D - Dependency Inversion)
Решение: Low Coupling через интерфейсы
// ✅ ХОРОШО: Low coupling — через интерфейсы
// Определяем интерфейсы (абстракции)
public interface IOrderDatabase {
Order save(Order order);
Order findById(String id);
}
public interface IEmailService {
void sendConfirmation(String email);
void sendNotification(String email, String message);
}
public interface IPaymentProcessor {
PaymentResult charge(BigDecimal amount, String cardToken);
void refund(String transactionId);
}
// Конкретные реализации
@Component
public class MySQLDatabase implements IOrderDatabase {
// Реализация
}
@Component
public class SendGridEmailService implements IEmailService {
// Реализация
}
@Component
public class PayPalPaymentProcessor implements IPaymentProcessor {
// Реализация
}
// Контроллер зависит от интерфейсов, а не от конкретных классов
@Controller
public class OrderController {
private final IOrderDatabase database; // Зависимость от интерфейса
private final IEmailService emailService; // Зависимость от интерфейса
private final IPaymentProcessor processor; // Зависимость от интерфейса
// Dependency Injection через конструктор
@Autowired
public OrderController(
IOrderDatabase database,
IEmailService emailService,
IPaymentProcessor processor) {
this.database = database;
this.emailService = emailService;
this.processor = processor;
}
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
Order order = database.save(new Order(request));
emailService.sendConfirmation(request.getEmail());
processor.charge(request.getAmount(), request.getCardToken());
return order;
}
}
Преимущества Low Coupling
// 1. ЛЁГКО ТЕСТИРОВАТЬ: можно подменить зависимости на mock'и
@ExtendWith(MockitoExtension.class)
public class OrderControllerTest {
@Mock
private IOrderDatabase database;
@Mock
private IEmailService emailService;
@Mock
private IPaymentProcessor processor;
@InjectMocks
private OrderController controller;
@Test
public void testCreateOrder() {
OrderRequest request = new OrderRequest("test@example.com", 100.00);
Order expectedOrder = new Order(request);
// Подменяем реальные реализации на mock'и
when(database.save(any())).thenReturn(expectedOrder);
when(processor.charge(any(), any()))
.thenReturn(new PaymentResult("success"));
Order result = controller.createOrder(request);
// Проверяем что методы были вызваны
verify(emailService).sendConfirmation(request.getEmail());
assertEquals(expectedOrder, result);
}
}
// 2. ЛЕГКО МЕНЯТЬ РЕАЛИЗАЦИЮ: просто создаёшь новый класс
@Component
public class PostgresDatabase implements IOrderDatabase {
// Новая реализация для PostgreSQL
// OrderController не нужно менять!
}
// 3. ЛЕГКО ДОБАВЛЯТЬ НОВЫЕ ФУНКЦИИ: через декораторы или новые реализации
@Component
public class CachingOrderDatabase implements IOrderDatabase {
private final IOrderDatabase delegate;
private final Cache<String, Order> cache;
@Override
public Order save(Order order) {
Order saved = delegate.save(order);
cache.put(order.getId(), saved);
return saved;
}
@Override
public Order findById(String id) {
return cache.getOrElse(id, () -> delegate.findById(id));
}
}
Принципы достижения Low Coupling
// 1. ЗАВИСИМОСТЬ ИНВЕРСИЯ (Dependency Inversion Principle)
// Зависи от абстракций, не от конкретных реализаций
@Service
public class GoodService {
private final SomeInterface dependency; // ✅ Зависимость от интерфейса
public GoodService(SomeInterface dependency) {
this.dependency = dependency;
}
}
// 2. ИНВЕРСИЯ УПРАВЛЕНИЯ (Inversion of Control)
// Spring контейнер создаёт объекты и внедряет зависимости
@Configuration
public class AppConfig {
@Bean
public IOrderDatabase orderDatabase() {
return new MySQLDatabase();
}
@Bean
public OrderController orderController(IOrderDatabase database) {
return new OrderController(database);
}
}
// 3. СЛАБАЯ СВЯЗЬ ЧЕРЕЗ СОБЫТИЯ (Event-Driven Architecture)
@Component
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createOrder(Order order) {
// Сохраняем заказ
// Публикуем событие (другие компоненты могут слушать)
eventPublisher.publishEvent(new OrderCreatedEvent(order));
}
}
// Другой сервис слушает событие (не знает о OrderService)
@Component
public class EmailNotificationService {
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
sendConfirmationEmail(event.getOrder().getEmail());
}
}
Архитектурные паттерны для Low Coupling
// 1. DEPENDENCY INJECTION (DI)
@Service
public class Service {
private final Dependency dep;
public Service(Dependency dep) { // Внедрение через конструктор
this.dep = dep;
}
}
// 2. REPOSITORY PATTERN
public interface UserRepository {
User findById(String id);
void save(User user);
}
@Service
public class UserService {
private final UserRepository repository; // Зависимость от интерфейса
public UserService(UserRepository repository) {
this.repository = repository;
}
}
// 3. ADAPTER PATTERN: адаптер для преобразования интерфейсов
public class LegacySystemAdapter implements IModernInterface {
private final LegacySystem legacy;
@Override
public void doSomething() {
// Преобразуем вызов в формат legacy системы
legacy.doLegacyAction();
}
}
Low Coupling vs High Cohesion
// ✅ ХОРОШО: Low Coupling + High Cohesion
// Low Coupling: компоненты слабо связаны
public interface PaymentService {
PaymentResult process(Payment payment);
}
// High Cohesion: внутри класса всё связано с одной задачей
@Service
public class StripePaymentService implements PaymentService {
// Все методы связаны с обработкой платежей через Stripe
private String validateCard(Card card) { ... }
private String chargeCard(Card card, BigDecimal amount) { ... }
private String handleError(StripeException ex) { ... }
@Override
public PaymentResult process(Payment payment) {
Card card = validateCard(payment.getCard());
return new PaymentResult(chargeCard(card, payment.getAmount()));
}
}
Заключение
Low coupling — это один из самых важных принципов в архитектуре ПО. Он:
- Упрощает тестирование
- Облегчает поддержку и расширение
- Снижает риск регрессий при изменениях
- Улучшает переиспользуемость кода
- Делает систему более гибкой и масштабируемой
Добиваются низкой связанности через использование интерфейсов, dependency injection, паттернов проектирования и правильного разделения ответственности между компонентами.