특징점 매칭을 적용해서 코드를 작성하려고 하니까 코드가 점점 길어지기 시작했다. 따라서 코드를 짧게 바꿀만한 방법이 없을지 찾아보다가 MVVM 패턴이 흔히 쓰이는 것을 발견하고 알아보기로 했다.
MVVM 패턴은 Model-View-ViewModel의 약자로, 애플리케이션의 비즈니스 로직과 UI를 분리하여 개발하는 디자인 패턴이다.
MVVM 패턴의 주요 구성 요소
음식점에서 주방과 홀이 분리된 것과 같다고 보면 될 것 같다. 주방에서는 요리사가 요리를 만들고(비즈니스 로직), 홀에서는 손님이 음식을 주문하고 먹는다(UI). 주방과 홀은 서로 분리되어 있지만, 주문서(ViewModel)를 통해 정보를 주고받는다.
: 애플리케이션에서 사용할 데이터와 이 데이터를 처리하는 비즈니스 로직을 클래스로 정의한다. 예를 들어, 사용자 정보를 관리하는 애플리케이션이라면 User 클래스를 Model로 정의하고, 사용자 이름, 나이, 주소 등의 데이터와 사용자 정보를 추가, 수정, 삭제하는 로직을 포함할 수 있다.
Model은 View와 ViewModel에 독립적이어야 한다. 즉, UI나 애플리케이션의 다른 부분에 대한 의존성 없이 순수하게 데이터와 비즈니스 로직만을 포함해야 한다.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
: 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>
: 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));
}
}
: XAML에서 데이터 바인딩을 사용하여 View의 컨트롤과 ViewModel의 프로퍼티를 연결한다. {Binding} 마크업 확장을 사용하여 데이터 바인딩을 표현한다.
<TextBox Text="{Binding Name}" />
: XAML에서 명령을 사용하여 View의 이벤트를 ViewModel의 메서드에 연결한다. ICommand 인터페이스를 구현하여 명령을 정의한다.
<Button Content="Save" Command="{Binding SaveCommand}" />
public ICommand SaveCommand { get; set; }
정리
DataContext 속성을 사용하여 View를 ViewModel에 연결한다.INotifyPropertyChanged 인터페이스를 구현하여 데이터 변경 알림을 지원한다.{Binding} 마크업 확장을 사용하여 데이터 바인딩을 표현한다.ICommand 인터페이스를 구현하여 명령을 정의한다.MVVM 패턴 자체가 성능 저하를 일으키는 것은 아니지만, MVVM 패턴을 잘못 적용하면 성능 저하가 발생할 수 있다고 한다. 특히, 나처럼 실시간 영상 처리와 같은 성능이 중요한 애플리케이션에서는 MVVM 패턴을 적용할 때 주의해야 할 것으로 판단된다. 그 이유는 다음과 같다.
MVVM 패턴 적용 시 성능 저하 가능성
INotifyPropertyChanged 인터페이스를 사용하여 속성 변경 알림을 구현할 때, 불필요하게 알림을 발생시키면 UI 업데이트가 빈번하게 발생하여 성능 저하를 일으킬 수 있다.MVVM 패턴 적용 시 성능 저하 방지 방법
MVVM 패턴 사용을 위한 단계
MVVM 패턴은 디자인 패턴이므로 Nuget에서 패키지를 설치하거나 using으로 참조해야 하는 것은 없다. 하지만 MVVM 패턴을 좀 더 쉽게 구현하기 위해 다음과 같은 라이브러리를 사용할 수 있다.
ViewModelBase 클래스, RelayCommand 클래스, Messenger 클래스 등을 제공한다. Nuget에서 MvvmLightLibs 패키지를 설치하여 사용할 수 있다.Prism.Core 패키지를 설치하여 사용할 수 있다.reactiveui 패키지를 설치하여 사용할 수 있다.