MVVM을 사용하여 더 나은 어플리케이션 만들기

본 논문에서 MVVM이 무엇인지, 그리고 더 좋은 웹/데스크톱 프로그램을 만드는 데 어떻게 도움이 되는지 설명하겠습니다.내 예시에서, 나는 C#/WPF를 사용하지만, 당신은 OOP와 HTML의 기본 지식을 습득할 수 있어야 합니다.

배경.


한 달 전까지만 해도 그래픽 사용자 인터페이스를 만든 경험은 일반적인 HTML/CSS 사이트와 appJar을 사용하는 기본python 응용 프로그램에만 한정되었다.나는 항상 GUI를 사용해야 한다는 개념에 놀랐다. 백엔드를 대상으로 하는 프로그래머로서 나의 사고방식은 유행의 틀과 잘 맞지 않는 것 같다.

최근에 나는 어쩔 수 없이 나의 decentralized social media을 위해 데스크톱 클라이언트를 개발하기 시작했다.대다수의 사람들이 동의할 것이다. 이것은 두려운 프로젝트이며, 특히 경험이 부족한 전단 개발자에게는 그렇다.처음에 나는 MVVM에 대해 알게 될 때까지 진보하기 어렵다는 것을 알았다.

MVVM이란 무엇입니까?


MVVM은 모델, 뷰, 뷰 모델을 나타냅니다.MVVM 애플리케이션의 세 가지 주요 부분을 구성합니다.

모델


모델은 응용 프로그램이 사용하는 핵심 알고리즘과 데이터 구조인'업무 논리'를 포함한다.그것들은 보통 '순수' 프로그래밍 언어로 작성되며, 특별한 라이브러리를 사용하지 않는다.

모델 보기


뷰 모델은 뷰 상태를 나타내는 특수 클래스입니다.예를 들어 텍스트를 표시하거나 사용자가 입력한 텍스트 상자 또는 다른 뷰 모델을 나타내는 속성이 있습니다.이벤트를 나타내는 기능/명령도 있어야 합니다(예를 들어 단추를 눌렀을 때).
뷰 모델에는 일반적으로 템플릿 코드가 있으므로 현재 사용 중인 MVVM 프레임워크와 통합할 수 있습니다.그러나 보기에 의존하지 않고 독립적으로 일해야 한다.

소견


보기에는 UI에서 사용하는 코드가 포함되어 있습니다.일반적으로 XAML 또는 HTML 등의 태그 언어로 작성됩니다.보기는 보기의 구조(과 스타일)를 개괄하고 그 내용은 귀속을 통해 설정됩니다.
귀속은 내용을 보기 모델에 연결할 수 있는 속성입니다.뷰 모델의 속성을 변경하면 뷰에 표시되는 내용이 자동으로 업데이트됩니다.귀속도 다른 방식으로 작업할 수 있으며 양방향 귀속을 사용할 수 있다.이것은 키를 눌렀을 때마다 보기 모델 속성을 업데이트할 수 있기 때문에 텍스트 상자에 유용합니다. (이것은 실시간 입력 검증에 사용할 수 있습니다.)

간단한 예


제가 방금 말씀드린 아이디어를 보여드리기 위해서 MVVM을 사용하여 프로그램을 만드는 과정을 신속하게 안내해 드리겠습니다.이 프로그램은 사용자가 인원 목록을 클릭할 수 있도록 할 것이다.
WPF(Windows 데모 프레임워크)를 사용합니다.계속하려면 VisualStudio에서 새 WPF App (.NET) 프로젝트를 만듭니다.제 전화번호는 Demo입니다.

모델 생성하기


우선, 우리는 한 사람을 나타내는 클래스를 만들 것이다.이 필드는 NameAge 두 필드로 구성됩니다.
나는 이미 이 종류를 Demo.Models 명칭 공간에 넣고 Models/PersonModel.cs으로 저장했다.
public class PersonModel
{
    public string Name { get; set; }
    public int Age { get; set; }

    public PersonModel(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

뷰 모델 생성하기


다음에 우리는 보기 모형을 만들 것이다.네 개의 속성이 있습니다. - 두 개의 문자열과 두 개의 명령이 있습니다.문자열은 현재 보이는 사람의 이름과 나이를 표시하고, 단추를 누르면 이들을 클릭할 수 있습니다.
속성을 변경할 때마다 뷰를 업데이트할 수 있도록 프레임에 경고해야 합니다.WPF에서는 INotifyPropertyChanged을 구현한 다음 속성을 설정할 때 NotifyPropertyChanged을 호출하여 구현합니다.
나는 이미 이 종류를 Demo.ViewModels 명칭 공간에 넣고 ViewModels/PeopleViewModel.cs으로 저장했다.
public class PeopleViewModel : INotifyPropertyChanged
{
    //// Bindable properties

    private string _name;

    public string Name
    {
        get => _name;
        private set
        {
            _name = value;
            NotifyPropertyChanged(nameof(Name));
        }
    }

    private string _age;

    public string Age
    {
        get => _age;
        private set
        {
            _age = value;
            NotifyPropertyChanged(nameof(Age));
        }
    }

    public ICommand Previous { get; init; }

    public ICommand Next { get; init; }

    //// Implementation

    private PersonModel[] people = new PersonModel[] {
        new PersonModel("Alice", 20),
        new PersonModel("Bob", 25),
        new PersonModel("Charlie", 30)
    };

    private int index = 0;

    public PeopleViewModel()
    {
        Name = people[index].Name;
        Age = people[index].Age.ToString();

        Previous = new RelayCommand(() =>
        {
            if (index > 0)
            {
                index--;
                Name = people[index].Name;
                Age = people[index].Age.ToString();
            }
        });

        Next = new RelayCommand(() =>
        {
            if (index < people.Length - 1)
            {
                index++;
                Name = people[index].Name;
                Age = people[index].Age.ToString();
            }
        });
    }

    //// Boilerplate code to satisfy INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged is null) return;
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
이 예에서 RelayCommand류는 함수를 ICommand으로 포장하는 데 사용된다.이에 대한 설명(그리고 이 종류의 코드)은 here에서 찾을 수 있다.

왜 나이가 정수가 아니에요?


age 속성은 정수가 아닙니다. 왜냐하면 이것은 사람의 나이를 대표하지 않기 때문입니다. 이것은 표시된 내용을 대표합니다.보기는 문자열을 표시하기 때문에 속성의 유형은string이어야 합니다.

뷰 생성하기


현재 보기 모형이 생성되었습니다. UserControl을 보기로 만들 것입니다.두 개의 탭과 두 개의 단추가 있습니다. 탭은 이름과 나이 문자열에 연결되고, 단추는 이전 명령과 다음 명령에 연결됩니다.
WPF에는 뷰당 DataContext이 있습니다.Demo.ViewModels 명칭 공간을 포함함으로써 우리는 사용자 컨트롤의 데이터 상하문을 PersonViewModel으로 설정할 수 있다.그리고 우리는 X 문법으로 UserControl.DataContext의 속성 "{Binding X}"에 귀속할 수 있다.
사용자 컨트롤을 Views/PeopleView.xaml으로 저장했습니다.
<UserControl x:Class="Demo.Views.PeopleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:viewmodels="clr-namespace:Demo.ViewModels"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.DataContext>
        <viewmodels:PeopleViewModel />
    </UserControl.DataContext>

    <StackPanel Background="White">
        <Label Content="{Binding Name}" />
        <Label Content="{Binding Age}" />
        <StackPanel Orientation="Horizontal">
            <Button Content="Previous" Command="{Binding Previous}" />
            <Label />
            <Button Content="Next" Command="{Binding Next}" />
        </StackPanel>
    </StackPanel>
</UserControl>

그럼 뒤에 코드는요?


코드 숨김은 MVVM을 사용하는 WPF 응용 프로그램에서 거의 사용되지 않습니다.모든 UI 논리는 숨겨진 코드가 아닌 뷰 모델에 포함되어야 합니다.이러한 관심사의 분리는 바로 MVVM이 이렇게 다기능 체계 구조가 된 원인이다!

끝맺다


현재 보기를 만들었습니다. MainWindow.xaml에 표시할 수 있습니다.
<Window x:Class="Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Demo.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <StackPanel>
        <views:PeopleView />
    </StackPanel>
</Window>
런타임 시 애플리케이션이 예상대로 작동하는 것을 보아야 합니다.

왜 이렇게 열심히 해요?


너는 우리가 왜 이렇게 노력해야 하는지 알고 싶을 것이다.MVVM이 표준 [코드 숨김] 방법보다 우수한 데는 세 가지 주요 이유가 있습니다.

테스트 가능성


뷰 모델과 뷰가 완전히 결합되어 있으므로 UI를 직접 테스트하지 않고도 테스트 프레임워크(예: MSTest)를 사용하여 인터페이스 논리가 정확한지 확인할 수 있습니다.

모듈화


모델과 보기 모델을 만들었으니 코드에서 구성 요소로 다시 사용할 수 있습니다.예를 들어, 다음과 같이 어셈블리의 두 번째 인스턴스를 추가할 수 있습니다.
<StackPanel>
    <views:PeopleView />
    <views:PeopleView />
</StackPanel>

구성 요소를 서로 끼워 넣으면 최소한의 작업량으로 복잡하고 모듈화된 사용자 인터페이스를 구축할 수 있습니다.
같은 보기 모형에 연결된 여러 보기를 만들 수 있습니다!나는 DataContextMainWindow을 새로운 PersonViewModel으로 설정하고 이 두 보기를 그것에 연결한다.
<Window x:Class="Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodels="clr-namespace:Demo.ViewModels"
        xmlns:views="clr-namespace:Demo.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <viewmodels:PeopleViewModel />
    </Window.DataContext>

    <StackPanel>
        <views:PeopleView DataContext="{Binding}" />
        <views:PeopleView DataContext="{Binding}" />
    </StackPanel>
</Window>

주의: 보통 보기의 DataContext 속성을 현재 보기 모델의 속성에 연결합니다.그러나 메인 창에 보기 모형이 없기 때문에 Window.DataContext으로 직접 연결합니다.

플랫폼 불가지론


응용 프로그램을 세 부분으로 나누면 여러 플랫폼에서 모델을 다시 사용하고 모델을 볼 수 있다.MvvmCross(Windows, Mac, iOS, 안드로이드 지원) 등 플랫폼 간 프레임워크를 사용하면 이 점이 쉬워진다.

결론


MVVM은 테스트, 모듈식 및 플랫폼 간 어플리케이션을 개발할 수 있는 어플리케이션 아키텍처입니다.코드는 세 부분으로 나뉘어져 있습니다.
  • 모델
  • 뷰 모델
  • 보기
  • 관심사의 분리는 코드의 유지보수성과 가독성을 향상시켰다.그 밖에 모델과 보기 모델은 크로스 플랫폼에서 단원 테스트와 공유를 할 수 있어 크로스 플랫폼 응용 프로그램을 더욱 빨리 개발할 수 있다.

    각주


    만약 당신이 이 글을 읽는 것을 좋아한다면 비슷한 글을 쓰거나 나를 따라오는 것을 고려해 보세요.



  • Github
  • 나는 이제 막 시작했으니, 당신의 지지에 매우 감사합니다!
    면책 성명 - 저는 독학으로 인재가 된 프로그래머입니다. 저는 블로그로 더 좋은 개발자가 되는 과정에서 배운 것을 공유합니다.나는 내가 저지른 모든 잘못에 대해 미리 사과한다. 비판과 정정을 환영한다.

    좋은 웹페이지 즐겨찾기