MVVM 패턴

00·2025년 1월 19일

개요

특징점 매칭을 적용해서 코드를 작성하려고 하니까 코드가 점점 길어지기 시작했다. 따라서 코드를 짧게 바꿀만한 방법이 없을지 찾아보다가 MVVM 패턴이 흔히 쓰이는 것을 발견하고 알아보기로 했다.

MVVM 패턴

MVVM 패턴?

MVVM 패턴은 Model-View-ViewModel의 약자로, 애플리케이션의 비즈니스 로직과 UI를 분리하여 개발하는 디자인 패턴이다.

MVVM 패턴의 주요 구성 요소

  • Model: 애플리케이션에서 사용되는 데이터와 비즈니스 로직을 나타낸다.
  • View: 사용자 인터페이스(UI)를 나타낸다. WPF에서는 XAML을 사용하여 View를 정의한다.
  • ViewModel: Model과 View 사이의 중개자 역할을 한다. Model에서 데이터를 가져와 View에 표시하고, View에서 발생하는 이벤트를 처리하여 Model에 업데이트한다.

음식점에서 주방과 홀이 분리된 것과 같다고 보면 될 것 같다. 주방에서는 요리사가 요리를 만들고(비즈니스 로직), 홀에서는 손님이 음식을 주문하고 먹는다(UI). 주방과 홀은 서로 분리되어 있지만, 주문서(ViewModel)를 통해 정보를 주고받는다.

MVVM 패턴의 장점

  • 개발 효율성: UI 디자이너와 개발자가 독립적으로 작업할 수 있어 개발 효율성을 높일 수 있다.
  • 테스트 용이성: ViewModel은 UI와 독립적으로 테스트할 수 있어 테스트가 용이하다.
  • 유지보수 용이성: UI 변경 시 ViewModel의 코드를 수정할 필요가 없어 유지보수가 용이하다.
  • 코드 재사용성: ViewModel은 여러 View에서 재사용할 수 있어 코드 재사용성을 높일 수 있다.

MVVM 패턴의 단점

  • 복잡성: MVVM 패턴은 MVC, MVP 등 다른 디자인 패턴에 비해 복잡할 수 있다.
  • 학습 곡선: MVVM 패턴을 처음 접하는 개발자는 학습하는 데 시간이 걸릴 수 있다.
  • 오버헤드: 데이터 바인딩 등을 사용하면 성능 오버헤드가 발생할 수 있다.

MVVM 패턴 사용 이유

  • UI와 비즈니스 로직을 분리하여 코드의 복잡성을 줄이고 유지보수성을 향상시키기 위해 사용한다.
  • 테스트 용이성을 높이기 위해 사용한다.
  • 코드 재사용성을 높이기 위해 사용한다.

MVVM 패턴 사용 방법

1. Model 정의

: 애플리케이션에서 사용할 데이터와 이 데이터를 처리하는 비즈니스 로직을 클래스로 정의한다. 예를 들어, 사용자 정보를 관리하는 애플리케이션이라면 User 클래스를 Model로 정의하고, 사용자 이름, 나이, 주소 등의 데이터와 사용자 정보를 추가, 수정, 삭제하는 로직을 포함할 수 있다.

Model은 View와 ViewModel에 독립적이어야 한다. 즉, UI나 애플리케이션의 다른 부분에 대한 의존성 없이 순수하게 데이터와 비즈니스 로직만을 포함해야 한다.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

2. View 정의

: XAML을 사용하여 UI를 정의한다.DataContext 속성을 사용하여 View를 ViewModel에 연결한다.

<Window ... >
 <Window.DataContext>
     <local:PersonViewModel />
 </Window.DataContext>
 <Grid>
     <StackPanel>
         <TextBox Text="{Binding Name}" />
         <TextBox Text="{Binding Age}" />
     </StackPanel>
 </Grid>
</Window>

3. ViewModel 정의

: Model과 View 사이의 중개자 역할을 하는 ViewModel 클래스를 정의한다. Model에서 데이터를 가져와 View에 표시하고, View에서 발생하는 이벤트를 처리하는 클래스를 정의한다. INotifyPropertyChanged 인터페이스를 구현하여 데이터 변경 알림을 지원한다.

public class PersonViewModel : INotifyPropertyChanged
{
    private Person person;

    public PersonViewModel()
    {
        person = new Person { Name = "John Doe", Age = 30 };
    }

    public string Name
    {
        get { return person.Name; }
        set
        {
            if (person.Name != value)
            {
                person.Name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    public int Age
    {
        get { return person.Age; }
        set
        {
            if (person.Age != value)
            {
                person.Age = value;
                OnPropertyChanged("Age");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

4. 데이터 바인딩

: XAML에서 데이터 바인딩을 사용하여 View의 컨트롤과 ViewModel의 프로퍼티를 연결한다. {Binding} 마크업 확장을 사용하여 데이터 바인딩을 표현한다.

<TextBox Text="{Binding Name}" />

5. 명령

: XAML에서 명령을 사용하여 View의 이벤트를 ViewModel의 메서드에 연결한다. ICommand 인터페이스를 구현하여 명령을 정의한다.

<Button Content="Save" Command="{Binding SaveCommand}" />
public ICommand SaveCommand { get; set; }

정리

  1. Model 정의: 애플리케이션에서 사용할 데이터와 비즈니스 로직을 클래스로 정의한다.
  2. View 정의: XAML을 사용하여 UI를 정의한다. DataContext 속성을 사용하여 View를 ViewModel에 연결한다.
  3. ViewModel 정의: Model과 View 사이의 중개자 역할을 하는 ViewModel 클래스를 정의한다.
    Model에서 데이터를 가져와 View에 표시하고, View에서 발생하는 이벤트를 처리하는 클래스를 정의한다. INotifyPropertyChanged 인터페이스를 구현하여 데이터 변경 알림을 지원한다.
  4. 데이터 바인딩: XAML에서 데이터 바인딩을 사용하여 View의 컨트롤과 ViewModel의 프로퍼티를 연결한다. {Binding} 마크업 확장을 사용하여 데이터 바인딩을 표현한다.
  5. 명령: XAML에서 명령을 사용하여 View의 이벤트를 ViewModel의 메서드에 연결한다. ICommand 인터페이스를 구현하여 명령을 정의한다.

적용 여부 판단

MVVM 패턴 자체가 성능 저하를 일으키는 것은 아니지만, MVVM 패턴을 잘못 적용하면 성능 저하가 발생할 수 있다고 한다. 특히, 나처럼 실시간 영상 처리와 같은 성능이 중요한 애플리케이션에서는 MVVM 패턴을 적용할 때 주의해야 할 것으로 판단된다. 그 이유는 다음과 같다.

MVVM 패턴 적용 시 성능 저하 가능성

  • 과도한 바인딩: 너무 많은 속성을 바인딩하거나, 복잡한 컨버터를 사용하면 바인딩 연산에 CPU 리소스를 많이 사용하게 되어 성능 저하가 발생할 수 있다.
  • 불필요한 속성 변경 알림: INotifyPropertyChanged 인터페이스를 사용하여 속성 변경 알림을 구현할 때, 불필요하게 알림을 발생시키면 UI 업데이트가 빈번하게 발생하여 성능 저하를 일으킬 수 있다.
  • ViewModel의 복잡성: ViewModel에 너무 많은 로직을 담거나, ViewModel 간의 의존성이 복잡하면 성능 저하가 발생할 수 있다.
  • 비동기 처리 부족: 실시간 영상 처리처럼 무거운 작업을 수행하는 경우, 비동기 처리를 하지 않으면 UI 스레드가 블록되어 성능 저하 및 UI 응답성 문제가 발생할 수 있다.

MVVM 패턴 적용 시 성능 저하 방지 방법

  • 바인딩 최적화: 필요한 속성만 바인딩하고, 간단한 컨버터를 사용한다.
  • 속성 변경 알림 최적화: 속성 값이 실제로 변경된 경우에만 알림을 발생시킨다.
  • ViewModel 단순화: ViewModel의 로직을 최대한 단순하게 유지하고, ViewModel 간의 의존성을 최소화한다.
  • 비동기 처리: 무거운 작업은 비동기적으로 처리하여 UI 스레드를 블록하지 않도록 한다.
  • 프로파일링: 성능 프로파일링 도구를 사용하여 성능 병목 현상을 파악하고, 코드를 최적화한다.

MVVM 패턴 사용을 위한 단계

MVVM 패턴은 디자인 패턴이므로 Nuget에서 패키지를 설치하거나 using으로 참조해야 하는 것은 없다. 하지만 MVVM 패턴을 좀 더 쉽게 구현하기 위해 다음과 같은 라이브러리를 사용할 수 있다.

  • MVVM Light: 간단하고 사용하기 쉬운 MVVM 프레임워크다. ViewModelBase 클래스, RelayCommand 클래스, Messenger 클래스 등을 제공한다. Nuget에서 MvvmLightLibs 패키지를 설치하여 사용할 수 있다.
  • Prism: Microsoft에서 제공하는 MVVM 프레임워크다. 모듈화, 의존성 주입, 네비게이션 등 다양한 기능을 제공한다. Nuget에서 Prism.Core 패키지를 설치하여 사용할 수 있다.
  • ReactiveUI: 반응형 프로그래밍을 위한 MVVM 프레임워크다. 비동기 처리, 이벤트 처리, 데이터 바인딩 등을 위한 다양한 기능을 제공한다. Nuget에서 reactiveui 패키지를 설치하여 사용할 수 있다.

참조

https://esound.tistory.com/22

https://devbong.tistory.com/36

https://kaki104.tistory.com/831

0개의 댓글