그림으로 느슨한 결합과 강한 결합을 설명하기 위해, 두 가지 다이어그램을 그릴 수 있다.
느슨한 결합 (Loose Coupling)
- 다이어그램: 인터페이스를 통해 구현체를 분리하여 의존성을 줄이는 구조
+----------------+ +----------------+
| ShoppingCart | | PaymentProcessor|
| |<------| (Interface) |
| - paymentProcessor | +----------------+
+----------------+ ^ ^
| |
| |
+----------------+ +----------------+
| PayPalProcessor| | StripeProcessor|
+----------------+ +----------------+
강한 결합 (Tight Coupling)
- 다이어그램: 클래스가 다른 클래스의 구체적인 구현에 직접 의존하는 구조
+----------------+ +----------------+
| ShoppingCart |------>| PayPalProcessor|
| | | |
| - paymentProcessor | | |
+----------------+ +----------------+
이 다이어그램들은 느슨한 결합과 강한 결합의 차이를 시각적으로 보여준다. 느슨한 결합에서는 ShoppingCart
가 PaymentProcessor
인터페이스에 의존하고, 구체적인 구현체는 인터페이스를 통해 주입된다.
반면, 강한 결합에서는 ShoppingCart
가 PayPalProcessor
구체적인 클래스에 직접 의존한다.
MVC 패턴을 통한 느슨한 결합을 살펴보면 아래와 같다.
서비스 인터페이스 생성: 서비스 계층을 위한 인터페이스를 정의한다.
서비스 인터페이스 구현: 서비스 인터페이스를 구현하는 클래스를 생성한다.
매퍼 인터페이스 생성: 데이터베이스 작업을 위한 MyBatis 매퍼 인터페이스를 정의한다.
매퍼 XML 생성: SQL 쿼리를 XML 파일에 정의한다.
컨트롤러 생성: 서비스 인터페이스를 사용하는 컨트롤러를 정의한다.
MyBatis 및 PostgreSQL 구성: application.properties에서 MyBatis 및 PostgreSQL 구성을 설정한다.
인터페이스란?인터페이스는 클래스가 구현해야 하는 메서드의 집합을 정의한다. 인터페이스를 사용하면 코드의 결합도를 낮추고 유연성을 높일 수 있다. 예를 들어, UserService 인터페이스는 사용자 서비스의 계약을 정의하며, 이를 구현하는 클래스는 인터페이스에 선언된 메서드를 반드시 구현해야 한다. 이를 통해 구현체를 쉽게 교체하거나 확장할 수 있다.
일단 코드는 일반적인 MVC 패턴으로 구현된 SpringBoot 코드이다. 코드는 아래의 Github에 업로드 하였다. (일반적인 RestAPI를 호출하여 테이블 리스트를 가져오는...)
- 폴더 구조를 보면 아래와 같다.
/project-root
|-- src
| |-- main
| |-- java
| |-- com
| |-- example
| |-- Loose
| |-- Coupling
| |-- mapper
| | |-- UserMapper.java
| |-- model
| | |-- User.java
| |-- service
| | |-- UserService.java
| | |-- impl
| | |-- UserServiceImpl.java
|-- build.gradle
|-- settings.gradle
이 프로젝트에서 느슨한 결합(Loose Coupling)이 적용된 부분은 UserService
인터페이스와 그 구현체 UserServiceImpl
클래스, 그리고 UserMapper
인터페이스 간의 관계이다.
느슨한 결합을 통해 각 구성 요소가 서로 독립적으로 변경될 수 있으며, 이는 유지보수성과 확장성을 높인다.
- 인터페이스 사용:
UserService
인터페이스는 사용자 서비스의 계약을 정의한다. 이 인터페이스는getAllUsers
메서드를 선언하고 있다.UserServiceImpl
클래스는UserService
인터페이스를 구현한다. 이 클래스는UserMapper
를 사용하여 실제 데이터베이스 작업을 수행한다.
- 의존성 주입:
UserServiceImpl
클래스는UserMapper
인터페이스에 의존한다. 이 의존성은 생성자 주입을 통해 주입됩니다. 이는 스프링 프레임워크의@Autowired
어노테이션을 사용하여 이루어진다.UserMapper
인터페이스는 MyBatis를 사용하여 데이터베이스와 상호작용한다. 이 인터페이스는@Mapper
어노테이션을 사용하여 MyBatis 매퍼로 등록된다.
- 구현체의 독립성:
UserServiceImpl
클래스는UserMapper
인터페이스에만 의존하며,UserMapper
의 구체적인 구현에 대해서는 알 필요가 없다. 이는UserMapper
의 구현이 변경되더라도UserServiceImpl
클래스가 영향을 받지 않음을 의미한다.
이러한 구조는 각 구성 요소가 서로 독립적으로 변경될 수 있도록 하여 시스템의 유연성을 높인다.
Github 코드는 아래와 같다.
https://github.com/Nanninggu/LooseCoupling_MVC
- 끝 -
'MSA (MicroServiceArchitecture) > MSA 개요 및 설계 관련' 카테고리의 다른 글
MSA에서 비동기 통신을 해야 하는 이유? (0) | 2024.08.26 |
---|---|
MSA에서 서비스 간 통신 오버헤드를 해결하기 위한 방법 (0) | 2024.08.21 |
3-Tier Architecture를 Micro Service Architecture로 전환할 때 서비스 분할 전략 (0) | 2024.08.21 |
MSA 아키텍처... (0) | 2023.03.29 |
Outer Architecture와 Inner Architecture의 이해 (0) | 2023.02.20 |