반응형
해당 포스팅은 개인적으로 C# WPF를 공부하면서 익힌 내용을 기억에 남기기 위한 작업의 일환으로 작성된 글로서
일부 내용에 오류가 있을 수도 있으니 참고하시기 바랍니다.

 

C#WPF에서 MVVM패턴으로 
프로그래밍 할때 Dependency Injection(DI)의
개념과 역할에 대해
알아보자.

 

반응형
내용 요약

 

MVVM (Model-View-ViewModel) 패턴은 WPF (Windows Presentation Foundation) 애플리케이션에서 UI와 비즈니스 로직을 분리하는 데 사용되는 아키텍처 패턴이다. 이 패턴은 코드의 재사용성과 테스트 용이성을 높이며, UI의 상태와 동작을 관리하는 ViewModel을 중심으로 구성된다. Dependency Injection (DI)은 이러한 MVVM 패턴을 구현할 때 매우 유용한 기법으로, 객체 간의 의존성을 관리하고, 코드의 결합도를 낮추는 데 도움을 준다.

 

목차
1.MVVM 패턴이란?
2.Dependency Injection 이란?
3.MVVM 패턴에서 Dependency Injection의 역할
4.WPF MVVM에서 DI 구현 예제
5.Dependency Injection 사용 시 주의할 점

 

1. MVVM 패턴이란?

 

MVVM(Model-View-ViewModel) 패턴은 WPF(Windows Presentation Foundation) 애플리케이션에서 자주 사용되는 아키텍처 패턴으로, 코드의 가독성과 유지보수성을 높이기 위해 설계되었다. MVVM은 세 가지 주요 컴포넌트로 구성된다.

 

Model: 애플리케이션의 데이터와 비즈니스 로직을 나타냄.

View: 사용자 인터페이스(UI) 요소를 담당하며, 데이터 바인딩(Data Binding)을 통해 ViewModel과 상호작용한다.

ViewModel: View와 Model 간의 중개 역할을 하며, View에 필요한 데이터를 제공하고 명령(Command)을 처리한다.

 

MVVM 패턴을 따를 때, View와 ViewModel은 느슨하게 결합되어야 하며, 이는 테스트 가능성과 확장성을 높이는 데 기여한다. 여기서 Dependency Injection(DI)은 ViewModel과 Model, 서비스 간의 의존성을 효과적으로 관리하는 데 중요한 역할을 한다.

 

2. Dependency Injection이란?

 

**Dependency Injection(DI)**는 객체 간의 의존성을 외부에서 주입하는 설계 패턴이다. 객체가 스스로 필요한 의존성을 생성하거나 관리하지 않고, 외부에서 주입받음으로써 코드의 유연성과 테스트 용이성을 높인다.

 

Dependency Injection의 핵심 개념

 

1. 의존성(Dependency): 한 클래스가 다른 클래스의 기능을 사용하려면 해당 클래스에 의존해야 한다. 예를 들어, ViewModel이 데이터 저장소를 사용해야 한다면, 이 저장소(Repository)가 ViewModel의 의존성이다.

2. 주입(Injection): 의존성을 직접 생성하지 않고 외부에서 필요한 객체를 주입한다.

3. 느슨한 결합(Loose Coupling): DI를 통해 클래스 간의 결합도를 낮추고, 변경 사항이 최소화되도록 설계한다.

 

DI의 종류

 

DI는 객체를 주입하는 방식에 따라 세 가지 유형으로 나뉜다.

생성자 주입(Constructor Injection): 의존성을 생성자의 매개변수로 전달.

속성 주입(Property Injection): 의존성을 객체의 속성을 통해 전달.

메서드 주입(Method Injection): 의존성을 메서드 호출 시 전달.

 

3. MVVM 패턴에서 Dependency Injection의 역할

 

WPF에서 MVVM 패턴을 사용할 때 Dependency Injection은 다음과 같은 역할을 한다:

1. ViewModel 생성 및 관리

DI는 ViewModel의 의존성을 주입하고 객체 생성을 관리한다.

이를 통해 ViewModel의 독립성을 유지하며, 단위 테스트가 용이해진다.

2. 서비스 및 데이터 액세스 계층의 주입

데이터 액세스 계층(예: Repository 패턴) 또는 서비스 클래스(예: API 호출)를 ViewModel에 주입하여 분리된 로직을 재사용할 수 있다.

3. 전역 상태 관리

DI 컨테이너를 사용하면 애플리케이션 전체에서 공유해야 하는 전역 서비스(예: 설정, 인증 상태)를 관리할 수 있다.

 

4. WPF MVVM에서 DI 구현 예제

 

다음은 DI를 사용하여 MVVM 패턴을 구현하는 간단한 예제이다.

 

(1) 프로젝트 설정

 

1. NuGet 패키지 설치

Microsoft.Extensions.DependencyInjection 패키지를 설치하여 DI 컨테이너를 사용한다.

 

(2) Model 정의

public class DataModel
{
    public string GetData() => "Hello, Dependency Injection!";
}

 

(3) Service Interface 정의

 

public interface IDataService
{
    string FetchData();
}

public class DataService : IDataService
{
    private readonly DataModel _dataModel;
    public DataService(DataModel dataModel)
    {
        _dataModel = dataModel;
    }
    public string FetchData() => _dataModel.GetData();
}

 

(4) ViewModel 정의

 

using System.ComponentModel;

public class MainViewModel : INotifyPropertyChanged
{
    private readonly IDataService _dataService;
    private string _displayData;
    public string DisplayData
    {
        get => _displayData;
        set
        {
            _displayData = value;
            OnPropertyChanged(nameof(DisplayData));
        }
    }

    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
        LoadData();
    }

    private void LoadData()
    {
        DisplayData = _dataService.FetchData();
    }

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

 

(5) DI(의존성 주입) 컨테이너 설정

 

using Microsoft.Extensions.DependencyInjection;

public partial class App : Application
{
    public static ServiceProvider ServiceProvider { get; private set; }
    protected override void OnStartup(StartupEventArgs e)
    {
        var services = new ServiceCollection();

        // DI 등록
        services.AddSingleton<DataModel>();
        services.AddSingleton<IDataService, DataService>();
        services.AddSingleton<MainViewModel>();
        ServiceProvider = services.BuildServiceProvider();

        var mainWindow = new MainWindow
        {
            DataContext = ServiceProvider.GetRequiredService<MainViewModel>()
        };
        
        mainWindow.Show();
        base.OnStartup(e);
    }
}

 

(6) View (XAML) 정의

 

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Dependency Injection Example" Height="200" Width="400">
    <Grid>
        <TextBlock Text="{Binding DisplayData}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20"/>
    </Grid>
</Window>

 

5. Dependency Injection 사용 시 주의할 점

 

1. 과도한 의존성 주입

너무 많은 의존성을 주입하면 코드가 복잡해지고 관리가 어려워질 수 있으므로 필요한 최소한의 의존성만 주입하도록 설계해야 한다.

2. 서비스 수명 주기 관리

DI 컨테이너를 사용할 때 객체의 수명 주기(Transient, Scoped, Singleton)를 신중히 선택해야 한다. WPF에서는 대부분 Singleton이 적합하지만, 특정 경우에는 Transient가 유용할 수 있다.

3. DI 컨테이너에 과도한 의존

DI 컨테이너에 모든 것을 등록하려다 보면 의존성 주입의 장점이 감소할 수 있으니 중요한 의존성만 컨테이너에 등록해야 한다.

4. 유닛 테스트와 DI

DI는 유닛 테스트를 쉽게 만들어주지만, Mock 객체를 올바르게 사용하지 않으면 테스트가 복잡해질 수 있다. 인터페이스 기반 설계와 Mocking 라이브러리(예: Moq)를 활용하자.

5. 초기 설정 복잡성

DI를 도입하면 초기 설정이 복잡해질 수 있으므로, 프로젝트 초기 단계에서 DI를 도입할지 여부를 신중히 결정하자.

 


결론

 

WPF에서 MVVM 패턴을 사용할 때 Dependency Injection은 클래스 간의 결합도를 낮추고, 테스트 가능성과 유지보수성을 높이는 강력한 도구이다. DI는 ViewModel, Model, 서비스 계층 간의 의존성을 명확히 관리하고, 전역 상태를 효율적으로 다룰 수 있도록 돕는다. 하지만 과도한 의존성 주입을 피하고 서비스 수명 주기를 신중히 설계하여 복잡성을 최소화하는 것이 중요하다.

반응형

+ Recent posts