디자인 패턴

디자인 패턴 - MVC(Model-View-Controller)패턴에 대해 알아보자(+ MVP, MVVM)

근본넘치는개발자 2024. 11. 7. 23:19

2024.11.05 - [디자인 패턴] - 디자인 패턴에 대해 알아보자#5 옵저버 패턴 (Oberserver)

 

지난 시간에 이어 오늘은 MVC(Model-View-Controller) 패턴과


MVP(Mode-View-Presenter),
MVVM(Model-View-ViewModel)에 대해 알아보고자 합니다.

 

MVC 패턴은 몇 번 들어봤는데

찾다 보니 MVP, MVVM 패턴도 함께 설명하고 있기에 같이 정리해 봤습니다.

 

이전에 팩토리 패턴이랑 팩토리 메서드 같은 느낌으로 생각하시면 편할 겁니다.

응용한 버전들이랄까.

MVC( Model, View, Controller ) 패턴

 

이 패턴은 UI를 체계적으로 구현하기 위해 만들어진 패턴입니다.

이름처럼 Model, View, Controller 세 부분으로 나누어 

불필요한 종속성을 줄이는데 목적을 두고 있습니다.

 

Model에는 데이터

View에서는 사용자에게 데이터를 표시(UI)

Controller에서는 입력 및 로직을 처리합니다. (사용자 입력을 처리하고 Model을 조작)

 

MVC를 적용하다 보면 모델 데이터의 변경 사항을 수신하기 위한

뷰별 코드가 필요한 상황이 발생하게 될 텐데

이때 사용하는 게 MVP 패턴입니다.

 

MVP(Model-View-Presenter),

 MV는 알겠는데 이번엔 Presenter라는 처음 보는 녀석이 생겼습니다.

이 친구의 역할은 MV 사이에서 중재하는 역할을 담당합니다.

 

다만 이런 경우 View와 Model이 Presenter에 의존하는 문제가 발생합니다.

이 MVP에서 한발 더 나아간 패턴이 MVVM입니다.

 

MVVM(Model-View-ViewModel)

ViewModel은 View와 Model 사이에서

데이터 바인딩 기능을 통해 뷰모델 속성 변경이 자동으로 뷰에 반영되도록 합니다.

 

예시

 

MVC 패턴

더보기
// MVC 패턴 예시
namespace MVC {
    // Model
    public class CounterModel {
        private int count = 0;
        
        public int Count => count;
        
        public void Increment() {
            count++;
        }
    }
    
    // View
    public class CounterView : MonoBehaviour {
        public Text counterText;
        public Button incrementButton;
        private CounterController controller;
        
        public void SetController(CounterController controller) {
            this.controller = controller;
            incrementButton.onClick.AddListener(controller.OnIncrementClicked);
        }
        
        public void UpdateDisplay(int count) {
            counterText.text = count.ToString();
        }
    }
    
    // Controller
    public class CounterController {
        private CounterModel model;
        private CounterView view;
        
        public CounterController(CounterModel model, CounterView view) {
            this.model = model;
            this.view = view;
            view.SetController(this);
        }
        
        public void OnIncrementClicked() {
            model.Increment();
            view.UpdateDisplay(model.Count);
        }
    }
}

 

MVP 패턴

더보기
// MVP 패턴 예시
namespace MVP {
    // Model
    public class CounterModel {
        private int count = 0;
        
        public int Count => count;
        
        public void Increment() {
            count++;
        }
    }
    
    // View Interface
    public interface ICounterView {
        void SetCount(int count);
        event System.Action IncrementClicked;
    }
    
    // View
    public class CounterView : MonoBehaviour, ICounterView {
        public Text counterText;
        public Button incrementButton;
        
        public event System.Action IncrementClicked;
        
        private void Start() {
            incrementButton.onClick.AddListener(() => IncrementClicked?.Invoke());
        }
        
        public void SetCount(int count) {
            counterText.text = count.ToString();
        }
    }
    
    // Presenter
    public class CounterPresenter {
        private CounterModel model;
        private ICounterView view;
        
        public CounterPresenter(CounterModel model, ICounterView view) {
            this.model = model;
            this.view = view;
            
            view.IncrementClicked += OnIncrementClicked;
        }
        
        private void OnIncrementClicked() {
            model.Increment();
            view.SetCount(model.Count);
        }
    }
}

 

MVVP 패턴

더보기
// MVVM 패턴 예시
namespace MVVM {
    // Model
    public class CounterModel {
        private int count = 0;
        
        public int Count => count;
        
        public void Increment() {
            count++;
        }
    }
    
    // ViewModel
    public class CounterViewModel : INotifyPropertyChanged {
        private CounterModel model;
        private int displayCount;
        
        public event PropertyChangedEventHandler PropertyChanged;
        
        public int DisplayCount {
            get => displayCount;
            private set {
                displayCount = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DisplayCount)));
            }
        }
        
        public ICommand IncrementCommand { get; }
        
        public CounterViewModel(CounterModel model) {
            this.model = model;
            IncrementCommand = new RelayCommand(ExecuteIncrement);
            DisplayCount = model.Count;
        }
        
        private void ExecuteIncrement() {
            model.Increment();
            DisplayCount = model.Count;
        }
    }
    
    // View
    public class CounterView : MonoBehaviour {
        public Text counterText;
        public Button incrementButton;
        private CounterViewModel viewModel;
        
        private void Start() {
            viewModel = new CounterViewModel(new CounterModel());
            
            // 데이터 바인딩 설정
            viewModel.PropertyChanged += (sender, e) => {
                if (e.PropertyName == nameof(CounterViewModel.DisplayCount)) {
                    counterText.text = viewModel.DisplayCount.ToString();
                }
            };
            
            // 커맨드 바인딩
            incrementButton.onClick.AddListener(() => viewModel.IncrementCommand.Execute(null));
        }
    }
}

 

마무리 

오늘은 간단하게 MVC 패턴, MVP, MVVM 패턴에 대해 알아보았습니다.

 

신입은 아무래도 UI/UX 이런 걸 많이 다루다 보니

약간 신입을 위한 디자인패턴 느낌으로 소개하던데 ㅋㅋ

 

잘 익혀두었다가 적용해 봐야겠습니다.

 

참고한 자료 

 

https://youtu.be/fxlYxhhf83s?si=UorUKPazZG6UNGMl