MVC 패턴
MVC(Model-View-Controller) 패턴은 대규모 애플리케이션의 복잡성을 줄이고 유지보수성을 향상하기 위해 사용되는 대표적인 소프트웨어 아키텍처 패턴임.
“모델(Model)”, “뷰(View)”, “컨트롤러(Controller)”의 세 가지 구성요소를 분리하여 역할을 명확히 함으로써, 코드의 응집도를 높이고 결합도를 낮추는 효과를 얻을 수 있음.
MVC 패턴의 기본 개념
1-1. Model(모델)
애플리케이션의 핵심 비즈니스 로직과 데이터를 관리함.
데이터의 상태를 표현하거나, 이를 조작(저장, 수정, 삭제, 조회)하는 메서드를 포함함.
DB 연동(DAO, Repository)이나 비즈니스 규칙(도메인 로직)을 담당하는 Service 계층 등도 모델에 속한다고 볼 수 있음.
1-2. View(뷰)
사용자에게 보여지는 UI 요소를 담당함.
웹 애플리케이션 환경에서는 JSP, HTML, Thymeleaf, FreeMarker 등의 템플릿 엔진을 통해 화면을 구성함.
데스크톱 애플리케이션(예: Java Swing, JavaFX)에서는 Swing 컴포넌트, FXML 등을 이용해 GUI를 구성함.
뷰는 모델로부터 전달받은 데이터(또는 DTO)를 어떻게 시각적으로 표현할지에만 집중함.
1-3. Controller(컨트롤러)
사용자 입력(HTTP 요청, GUI 액션 등)을 받아서 모델과 상호작용한 뒤, 적절한 뷰에 데이터를 전달하거나 리다이렉트하는 역할을 함.
요청을 분석하고, 필요하다면 모델을 업데이트하거나 정보를 조회한 후, 이를 바탕으로 뷰를 결정함.
컨트롤러는 모델과 뷰를 연결하는 중재자(Mediator) 역할을 수행함.
MVC 패턴은 이 세 구성요소를 분리함으로써, 다음과 같은 장점을 제공함.
2-1. 유지보수성 및 확장성
뷰 로직을 변경해도 모델과 컨트롤러 로직에는 영향을 주지 않으므로, 화면(UI) 수정이 용이함.
반대로 비즈니스 로직을 개선해도, 뷰 단 코드를 크게 수정할 필요가 없음.
2-2. 테스트 용이성
모델과 컨트롤러가 분리되어 있으므로, JUnit 같은 테스트 프레임워크를 통해 모델 또는 컨트롤러 로직을 각각 독립적으로 테스트하기가 쉬움.
2-3. 역할 분담
대규모 팀에서 개발할 때, 프론트엔드/백엔드 역할 분담이 명확해짐.
Java Web 애플리케이션에서의 MVC
자바 웹 애플리케이션에서 MVC 패턴은 일반적으로 아래와 같은 계층으로 구성됨.
1. Model 계층
DB 접근(DAO, Repository)과 비즈니스 로직(Service)이 포함됨.
public class User {
private Long id;
private String username;
private String email;
// getter, setter, etc.
}
public interface UserRepository {
User findById(Long id);
void save(User user);
// ...
}
public class UserService {
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUser(Long id) {
return userRepository.findById(id);
}
public void createUser(User user) {
// 비즈니스 규칙 확인 등
userRepository.save(user);
}
}
2. View 계층
JSP, Thymeleaf, Spring Boot의 경우 HTML + Thymeleaf, JSF, Freemarker 등 사용자 인터페이스를 구성함.
Controller에서 넘겨준 데이터(ModelAndView 또는 Model 객체 등)를 받아 화면에 표시함.
<!-- userDetails.html -->
<html>
<body>
<h1>User Details</h1>
<p>ID: <span th:text="${user.id}"></span></p>
<p>Username: <span th:text="${user.username}"></span></p>
<p>Email: <span th:text="${user.email}"></span></p>
</body>
</html>
3. Controller 계층
Spring MVC 기준으로 예를 들면, @Controller 또는 @RestController가 붙은 클래스가 컨트롤러 역할을 담당함.
클라이언트의 요청(예: /user/detail)을 받고, 필요한 모델 로직을 호출한 뒤, 뷰 이름과 함께 데이터를 반환함.
@Controller
@RequestMapping("/user")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/detail")
public String userDetail(@RequestParam("id") Long id, Model model) {
User user = userService.getUser(id);
model.addAttribute("user", user);
return "userDetails"; // 뷰 이름(userDetails.html)
}
}
4. Spring MVC 흐름 정리
사용자가 /user/detail?id=1 요청을 보냄.
DispatcherServlet이 해당 요청을 UserController의 userDetail() 메서드로 라우팅.
컨트롤러는 UserService의 getUser() 호출로 모델(비즈니스 로직)과 상호작용.
비즈니스 로직 결과(예: User 객체)를 Model 객체에 담아 반환값으로 뷰 이름(userDetails)을 지정.
DispatcherServlet은 뷰 리졸버(ViewResolver)를 통해 userDetails.html 파일을 찾아 렌더링.
렌더링된 페이지(HTML)가 사용자에게 응답으로 전달.
Java 데스크톱 애플리케이션에서의 MVC
자바 데스크톱 개발 시에도 MVC 구조를 적용할 수 있음.
1. Model
public class UserModel {
private String username;
private String password;
// 생성자, getter, setter 등
}
2. View
public class LoginView extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
private JButton loginButton;
public LoginView() {
setTitle("Login");
setSize(300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
usernameField = new JTextField(15);
passwordField = new JPasswordField(15);
loginButton = new JButton("Login");
JPanel panel = new JPanel();
panel.add(new JLabel("Username:"));
panel.add(usernameField);
panel.add(new JLabel("Password:"));
panel.add(passwordField);
panel.add(loginButton);
add(panel);
}
public String getUsername() {
return usernameField.getText();
}
public String getPassword() {
return String.valueOf(passwordField.getPassword());
}
public void setLoginButtonAction(ActionListener listener) {
loginButton.addActionListener(listener);
}
}
3. Controller
public class LoginController {
private LoginView view;
private UserModel model;
public LoginController(LoginView view, UserModel model) {
this.view = view;
this.model = model;
// 뷰에서 로그인 버튼이 눌렸을 때의 액션 정의
this.view.setLoginButtonAction(e -> handleLogin());
}
private void handleLogin() {
model.setUsername(view.getUsername());
model.setPassword(view.getPassword());
// 모델에 대한 검증 로직 수행(데이터베이스 확인 등)
if (validateUser(model.getUsername(), model.getPassword())) {
JOptionPane.showMessageDialog(null, "Login successful!");
} else {
JOptionPane.showMessageDialog(null, "Invalid credentials.");
}
}
private boolean validateUser(String username, String password) {
// 간단한 예시
return "admin".equals(username) && "1234".equals(password);
}
}
위와 같이 데스크톱 환경에서도 MVC 구조를 적용할 수 있음.
모델은 데이터(사용자 정보)를 보관하고, 뷰는 UI 표시만 담당하며, 컨트롤러는 뷰와 모델을 연결하고 이벤트(버튼 클릭 등)에 대응함.
자바에서 MVC를 구현하는 대표적인 프레임워크
1. Spring MVC
스프링 프레임워크에서 가장 많이 쓰이는 모듈 중 하나이며, DispatcherServlet을 중심으로 MVC 아키텍처를 구현함.
의존성 주입(Dependency Injection)과 AOP(Aspect-Oriented Programming) 기능과 결합해, 확장성이 뛰어남.
RESTful API 개발 시 @RestController를 통해 JSON, XML 형식으로 응답을 쉽게 처리할 수 있음.
2. JSF(JavaServer Faces)
자바 EE 표준 스펙 중 하나로, 컴포넌트 기반 UI 프레임워크임.
JSP보다 높은 추상화 레벨로, UI 구성 요소(Managed Bean, Facelets 등)를 활용함.
하지만, Spring Boot 시대 이후에는 JSF 사용 빈도가 상대적으로 낮아지는 추세임.
3. Struts
한때 자바 웹 애플리케이션 표준으로 자리 잡았던 MVC 프레임워크임.
현재는 유지보수가 활발하지 않고, Spring MVC가 사실상 표준처럼 사용되고 있음.
4. Play Framework
비동기(Asynchronous) 아키텍처, 라우팅 DSL, 스칼라(Scala) 지원 등 기능을 갖춘 웹 프레임워크임.
JVM 위에서 동작하며, Java와 Scala 모두를 지원함.
5. JavaFX
데스크톱 클라이언트 UI 프레임워크로, FXML을 이용해 뷰를 구성하고, 컨트롤러를 통해 이벤트를 처리함.
MVC보다는 MVVM(Model-View-ViewModel) 아키텍처와 유사하게 동작하는 경우도 많음.
MVC 사용 시 주의사항
1. 지나친 로직 분산
컨트롤러에서 너무 많은 비즈니스 로직을 처리하지 않도록 주의해야 함(Controller가 비대해지는 문제).
비즈니스 로직은 Model(Service) 계층으로 최대한 분리하는 것이 바람직함.
2. View와 Model 간의 직접 결합 최소화
뷰가 모델 객체에 직접 의존할 경우, 모델 변경에 따라 뷰가 변해야 할 수도 있음.
DTO나 View Model 같은 전용 객체를 둬서 데이터 전달을 명확히 하는 것이 좋음.
3. Controller가 거대해지는 현상
하나의 컨트롤러가 너무 많은 엔드포인트와 로직을 처리하면 복잡도가 크게 올라감.
리소스(도메인)나 기능별로 컨트롤러를 분할하여 책임을 분산하는 것이 좋음.
4. 빈약한 Model
Model 계층이 단순히 데이터만 담고 있고, 실제 비즈니스 로직은 여기저기 흩어져 있으면 MVC 구조가 무의미해질 수 있음.
비즈니스 로직은 Model(Service 계층) 내부에서 처리하도록 집중시키는 것이 핵심임.
5. MVC 패턴의 변형
규모에 따라 MVP, MVVM, Layered Architecture, Hexagonal Architecture 등 더 세분화되거나 다른 아키텍처를 적용할 수도 있음.
MVC는 기본 설계 철학일 뿐, 프로젝트 특성에 따라 변경/확장이 가능함.
MVC 패턴의 장점과 단점
1. 장점
분리된 관심사(Separation of Concerns): 역할이 명확하게 구분되어 유지보수가 용이함.
테스트 및 협업 용이: 기능별로 코드를 분리할 수 있어, 테스트가 쉽고 협업도 수월함.
유연한 변경 가능: UI(View)를 교체하거나, 비즈니스 로직(Model)을 확장할 때, 다른 계층에 대한 영향이 최소화됨.
2. 단점
초기 설계 비용: 작은 프로젝트에서는 MVC를 엄격히 적용하는 것이 오버엔지니어링일 수 있음.
구현 복잡도 증가: 로직을 여러 계층에 나누다 보니, 구조가 복잡해질 수 있으며, 레이어 간 통신이 늘어남.
지나친 계층 분리: 설계 원칙을 지나치게 따르다 보면, 실제 비즈니스 요구사항에 비해 코드 구조가 과도하게 분할될 수 있음.
정리
자바(Java) 생태계에서 MVC 패턴은 전통적으로 가장 많이 사용되는 소프트웨어 아키텍처 패턴 중 하나임.
웹 애플리케이션(Spring MVC, Struts, JSF 등)은 물론이고, 데스크톱 애플리케이션(Swing, JavaFX)에서도 MVC 패턴을 적용해 기능을 모듈화하고 유지보수성을 높일 수 있음.
1. Model: 도메인 데이터 및 비즈니스 로직(서비스 계층) 담당.
2. View: 사용자에게 화면(UI)을 제공, 필요한 경우 모델에서 받은 데이터를 시각화.
3. Controller: 사용자 요청 처리, 모델과 뷰를 연결하는 중간자 역할.
중요한 것은 “MVC를 어떻게 적용하느냐”임.
단순히 계층만 나누어 놓았다고 해서 프로젝트가 자동으로 유지보수하기 쉬워지지 않음.
컨트롤러와 모델 사이의 결합, 뷰와 모델 사이의 데이터 전달 방식, 모델 내부의 비즈니스 로직 배치 등이 모두 적절하게 설계되어야 함.
프로젝트 규모가 커지면 MVC도 확장하거나, 다른 아키텍처(MVVM, Clean Architecture, Hexagonal Architecture 등)를 부분 도입하여 복잡도를 관리하는 것이 일반적임.
그러나 “하나의 패턴을 잘 이해하고, 상황에 맞춰 적절히 변형/적용”하는 것이 궁극적으로 중요한 개발자의 역량임.
결론적으로, 자바에서 MVC 패턴은 확고한 전통과 풍부한 프레임워크 지원을 갖추고 있음.
규모 있는 프로젝트라면 분명한 이점이 있으며, 전문가 수준으로 사용하기 위해서는 모델, 뷰, 컨트롤러 각각에 대한 책임 분배와 결합도 관리가 핵심임을 명심해야 함.
'Programming Language > Java' 카테고리의 다른 글
[java] 메이븐 설치 안됐을 때 확인하는 방법 (0) | 2022.01.01 |
---|---|
[java] "Hello" 출력하는 방법 (0) | 2021.12.13 |
[java] java란 (0) | 2021.06.03 |
[java] 이클립스 설치하기 2/2 (0) | 2021.06.03 |
[java] 이클립스 설치하기 1/2 (0) | 2021.06.03 |