7. MVVM에서의 ViewModel 간 통신과 메시징 시스템, Mediator 패턴을 사용한 ViewModel 간 통신
MVVM (Model-View-ViewModel) 패턴은 WPF (Windows Presentation Foundation) 애플리케이션에서 널리 사용되는 디자인 패턴입니다. MVVM의 주요 목적은 UI와 비즈니스 로직의 분리를 통해 유지보수성과 재사용성을 높이는 것입니다. 이 패턴에서 ViewModel은 View와 Model 간의 중재자 역할을 하며 데이터 바인딩을 통해 UI를 업데이트합니다. 그러나 애플리케이션이 복잡해짐에 따라 여러 ViewModel 간의 통신이 필요해지며, 이와 관련된 다양한 메커니즘이 필요합니다. 본 글에서는 ViewModel 간의 통신과 메시징 시스템, 그리고 Mediator 패턴을 사용한 ViewModel 간 통신을 자세히 살펴보겠습니다.
1. ViewModel 간 통신의 필요성
MVVM 패턴에서는 각 ViewModel이 특정한 뷰를 담당합니다. 그러나 대규모 애플리케이션에서는 여러 ViewModel이 상호작용해야 할 필요가 있습니다. 예를 들어, 사용자가 한 ViewModel에서 데이터를 입력하면 이 변화가 다른 ViewModel에 영향을 미칠 수 있습니다. 이러한 상황에서 ViewModel 간의 의사소통이 필수적입니다.
ViewModel 간의 통신을 필요로 하는 경우는 다음과 같습니다:
- 상태 공유: 여러 ViewModel이 동일한 데이터를 공유할 때
- 상호작용: 한 ViewModel의 작업 결과가 다른 ViewModel의 행동에 영향을 줄 때
- 이벤트 처리: 여러 ViewModel에서 특정 이벤트가 발생했을 때
2. ViewModel 간의 통신 방법
ViewModel 간의 통신을 위한 방법에는 여러 가지가 있습니다. 여기서는 두 가지 주요 방법인 메시징 시스템과 Mediator 패턴에 대해 설명합니다.
2.1. 메시징 시스템
메시징 시스템은 ViewModel 간의 통신을 지원하는 일반적인 방법입니다. 이 시스템에서는 한 ViewModel이 메시지를 발송하고 다른 ViewModel이 이를 수신하여 반응하는 방식으로 동작합니다. WPF에서는 MvvmLight 또는 Prism과 같은 라이브러리를 사용하여 메시징 시스템을 구현할 수 있습니다.
다음은 MvvmLight를 사용하여 메시징 시스템을 구현한 예제 코드입니다:
using GalaSoft.MvvmLight.Messaging;
public class FirstViewModel : ViewModelBase
{
public void DoAction()
{
// 작업 수행
Messenger.Default.Send(new NotificationMessage("Hello from FirstViewModel"));
}
}
public class SecondViewModel : ViewModelBase
{
public SecondViewModel()
{
Messenger.Default.Register(this, OnNotify);
}
private void OnNotify(NotificationMessage message)
{
if (message.Content.ToString() == "Hello from FirstViewModel")
{
// 메시지 처리
}
}
}
위 코드는 FirstViewModel이 action을 수행하면서 메시지를 보냅니다. SecondViewModel은 이 메시지를 수신하여 처리하는 구조입니다. 이와 같은 구조는 ViewModel 간의 느슨한 결합을 유지하면서도 각 ViewModel 간의 상호작용을 촉진합니다.
2.2. Mediator 패턴
Mediator 패턴은 객체 간의 상호작용을 조정하는 중재자로서 기능을 수행하는 디자인 패턴입니다. 이 패턴을 사용하면 상호작용하는 객체 간의 의존성을 줄이고, 객체들 간의 커뮤니케이션을 중앙 집중식으로 관리할 수 있습니다. MVVM에서 Mediator 패턴을 사용하여 ViewModel 간의 통신을 구현할 수 있습니다.
다음은 Mediator 패턴을 사용하여 ViewModel 간 통신을 구현한 예제 코드입니다:
public interface IMediator
{
void Register(string message, IReceiver receiver);
void Send(string message, object data);
}
public class Mediator : IMediator
{
private readonly Dictionary> _receivers = new();
public void Register(string message, IReceiver receiver)
{
if (!_receivers.ContainsKey(message))
{
_receivers[message] = new List();
}
_receivers[message].Add(receiver);
}
public void Send(string message, object data)
{
if (_receivers.ContainsKey(message))
{
foreach (var receiver in _receivers[message])
{
receiver.Receive(message, data);
}
}
}
}
public interface IReceiver
{
void Receive(string message, object data);
}
public class FirstViewModel : ViewModelBase, IReceiver
{
private readonly IMediator _mediator;
public FirstViewModel(IMediator mediator)
{
_mediator = mediator;
_mediator.Register("DoSomething", this);
}
public void DoAction()
{
// Action 수행 후 다른 ViewModel에게 알림
_mediator.Send("DoSomething", null);
}
public void Receive(string message, object data)
{
// 메시지 처리
}
}
public class SecondViewModel : ViewModelBase, IReceiver
{
private readonly IMediator _mediator;
public SecondViewModel(IMediator mediator)
{
_mediator = mediator;
_mediator.Register("DoSomething", this);
}
public void Receive(string message, object data)
{
if (message == "DoSomething")
{
// 메시지 처리
}
}
}
위 코드에서 Mediator 클래스는 다양한 ViewModel을 등록하고, 특정 메시지를 수신하면 등록된 ViewModel에 알리는 역할을 합니다. 각 ViewModel은 Mediator로부터 메시지를 수신하기 위해 IReceiver 인터페이스를 구현해야 합니다. 이 구조는 ViewModel 간의 결합도를 낮추고, 각 ViewModel 간의 통신을 보다 명확하게 해줍니다.
3. 메시징 시스템과 Mediator 패턴 비교
메시징 시스템과 Mediator 패턴은 모두 ViewModel 간의 통신을 가능하게 해주지만, 각각의 접근 방식에는 장단점이 있습니다.
메시징 시스템의 장점:
- 구현이 간단하고 직관적입니다.
- 다양한 메시지를 통해 유연한 통신이 가능합니다.
단점:
- 메시지가 너무 많이 생기면 관리가 어려워질 수 있습니다.
- 메시지 처리 순서를 관리하기 어려울 수 있습니다.
Mediator 패턴의 장점:
- 각 ViewModel 간의 의존성을 줄이고, 중재자를 통해 통신을 처리하여 관리가 용이합니다.
- 메시지 처리 로직을 중앙 집중화하여 코드의 가독성을 높입니다.
단점:
- 구현이 상대적으로 복잡할 수 있으며, 초기 설정에 더 많은 코드가 필요할 수 있습니다.
- 하나의 Mediator가 모든 통신을 처리하므로, 단일 실패 지점이 될 수 있습니다.
4. 결론
MVVM 패턴에서 ViewModel 간의 통신은 애플리케이션의 복잡성을 관리하는 데 매우 중요합니다. 메시징 시스템과 Mediator 패턴은 각각의 장단점이 있으며, 애플리케이션의 요구사항에 따라 적절한 방법을 선택하여 사용할 수 있습니다. 이 두 가지 방법을 통해 ViewModel 간의 통신을 보다 효율적으로 구현하고, UI와 비즈니스 로직의 분리를 유지할 수 있습니다. 이를 통해 유지보수성과 확장성을 갖춘 WPF 애플리케이션을 개발할 수 있습니다.
이러한 기술들은 커다란 애플리케이션을 구축하는 데 있어 필수적으로 익혀야 할 부분입니다. 개발자는 상황에 따라 가장 적합한 방법을 선택하여 사용하고, 각 ViewModel의 lifecycle과 상태를 잘 관리하여 애플리케이션의 품질을 높여야 합니다.
앞으로 더 많은 WPF 및 MVVM 관련 주제를 다루며, 복잡한 애플리케이션에서의 개발 기술과 경험을 공유할 예정입니다.