소프트웨어 디자인 패턴 - 1. MVC 패턴 (Model-View-Controller)

2025. 1. 19. 23:38소프트웨어/디자인 패턴

MVC 패턴이란?

MVC 패턴은 애플리케이션을 Model, View, Controller의 세 가지 역할로 나누어 설계하는 소프트웨어 디자인 패턴입니다. 이를 통해 역할을 명확히 분리하고 코드의 유지보수성과 확장성을 높입니다.


구성 요소

1. Model

  • 데이터를 관리하고 저장하는 역할.
  • 데이터베이스와 상호작용.
  • 상태를 유지하며 데이터 구조를 정의.

Note: 비즈니스 로직은 일반적으로 Controller나 별도의 Service 계층에서 처리하며, Model은 데이터 관리에 집중.

2. View

  • 사용자 인터페이스(UI)를 나타냄.
  • 데이터를 화면에 표시하며, 사용자 입력을 Controller로 전달.

3. Controller

  • 사용자 요청을 처리하고 Model과 View를 연결.
  • 비즈니스 로직을 처리하며, Model에 데이터를 요청하거나 View에 데이터를 전달.

MVC의 장점

  1. 역할 분리: 각 구성 요소가 독립적으로 동작.
  2. 유지보수 용이: 변경 사항이 다른 구성 요소에 영향을 덜 미침.
  3. 테스트 용이성: Model과 Controller를 독립적으로 단위 테스트 가능.
  4. 확장성: 새로운 View 추가 및 기능 확장이 용이.

C++ 예제 코드: 도서 관리 프로그램

구현된 기능

  1. 사용자 입력을 통해 책 정보를 추가.
  2. 추가된 책 목록을 출력.
  3. 잘못된 입력에 대한 에러 처리.
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
using namespace std;

// Model: 도서 데이터 정의
class Book {
public:
    string title;
    string author;
    int year;

    Book(string title, string author, int year)
        : title(title), author(author), year(year) {}
};

// Model: 도서 데이터 관리
class BookModel {
private:
    vector<Book> books;

public:
    void addBook(const string& title, const string& author, int year) {
        if (title.empty() || author.empty() || year <= 0) {
            throw invalid_argument("Invalid book data.");
        }
        books.emplace_back(title, author, year);
    }

    vector<Book> getBooks() {
        return books;
    }
};

// View: UI 출력 및 사용자 입력 처리
class BookView {
public:
    void displayBooks(const vector<Book>& books) {
        cout << "Book List:" << endl;
        for (const auto& book : books) {
            cout << "Title: " << book.title << ", Author: " << book.author << ", Year: " << book.year << endl;
        }
        cout << endl;
    }

    void displayMessage(const string& message) {
        cout << message << endl;
    }

    string getUserInput(const string& prompt) {
        cout << prompt;
        string input;
        getline(cin, input);
        return input;
    }

    int getUserInputInt(const string& prompt) {
        cout << prompt;
        int input;
        cin >> input;
        cin.ignore(); // Clear the newline from input buffer
        return input;
    }
};

// Controller: 로직 처리 및 예외 핸들링
class BookController {
private:
    BookModel& model;
    BookView& view;

public:
    BookController(BookModel& model, BookView& view)
        : model(model), view(view) {}

    void addBook() {
        try {
            string title = view.getUserInput("Enter book title: ");
            string author = view.getUserInput("Enter author name: ");
            int year = view.getUserInputInt("Enter publication year: ");
            model.addBook(title, author, year);
            view.displayMessage("Book added successfully!");
        } catch (const exception& e) {
            view.displayMessage(string("Error: ") + e.what());
        }
    }

    void showBooks() {
        vector<Book> books = model.getBooks();
        if (books.empty()) {
            view.displayMessage("No books found.");
        } else {
            view.displayBooks(books);
        }
    }
};

// Main: 애플리케이션 실행
int main() {
    BookModel model;
    BookView view;
    BookController controller(model, view);

    while (true) {
        cout << "1. Add Book" << endl;
        cout << "2. Show Books" << endl;
        cout << "3. Exit" << endl;
        int choice = view.getUserInputInt("Choose an option: ");

        switch (choice) {
        case 1:
            controller.addBook();
            break;
        case 2:
            controller.showBooks();
            break;
        case 3:
            return 0;
        default:
            view.displayMessage("Invalid choice. Please try again.");
        }
    }
}

코드 설명

Model

  • Book: 개별 책 데이터를 정의.
  • BookModel: 책 데이터를 저장하고 관리.

View

  • 사용자에게 책 목록을 출력하거나 메시지를 표시.
  • 사용자 입력을 처리.

Controller

  • 사용자 입력에 따라 Model과 View를 연결.
  • 예외 처리로 에러 상황을 관리.

웹 애플리케이션에서의 MVC

구성

  1. Model: 데이터베이스와 상호작용하여 데이터 저장.
  2. View: HTML, CSS로 작성된 사용자 인터페이스.
  3. Controller: HTTP 요청을 받아 Model과 View를 연결.

예시: 사용자 등록 시스템

  • Model: 사용자 데이터를 저장하는 데이터베이스 테이블.
  • View: 사용자 등록 폼.
  • Controller: 사용자 입력 데이터를 검증하고 데이터베이스에 저장.

장점

  1. 유지보수 용이: 구성 요소가 독립적이므로 수정이 다른 요소에 영향을 덜 미침.
  2. 테스트 용이성: Model과 Controller를 각각 단위 테스트 가능.
  3. 확장성: 새로운 View나 기능 추가가 간단.

테스트 용이성 구체화

  • Model 테스트: "데이터 추가 및 조회 기능이 정상적으로 작동하는가?"
  • Controller 테스트: "유효하지 않은 데이터를 입력했을 때 에러 처리가 제대로 되는가?"
  • View 테스트: "UI가 올바르게 데이터를 표시하는가?"

이 보완된 구조와 설명을 통해 MVC 패턴을 명확히 이해하고, 실제 프로젝트에 효과적으로 활용할 수 있습니다.