본문 바로가기
Flutter

플러터에서 MVP 패턴 사용 방법 및 장단점

by Maccrey Coding 2024. 7. 30.
728x90
반응형

 

플러터는 빠른 개발 속도, 풍부한 기능, 아름다운 UI를 제공하며 모바일 앱 개발 분야에서 큰 인기를 얻고 있습니다.

하지만, 복잡한 앱 개발 시에는 코드 구조, 유지 관리, 테스트 등 여러가지 어려움에 직면할 수 있습니다.

이러한 어려움을 해결하고 효율적인 앱 개발을 위해 디자인 패턴을 활용하는 것이 중요합니다.

디자인 패턴은 소프트웨어 개발에서 반복적으로 발생하는 문제를 해결하기 위한 재사용 가능한 솔루션입니다.

플러터에는 MVC, MVP, MVVM 등 다양한 디자인 패턴이 있으며, 각 패턴마다 장점과 단점, 그리고 사용 방법이 존재합니다.

이 블로그에서는 플러터에서 흔히 사용되는 디자인 패턴 중 하나인 MVP 패턴에 대해 심층적으로 분석하고, 장점과 단점, 그리고 사용 방법을 자세히 설명합니다.

1. MVP 패턴이란 무엇인가?

MVP (Model-View-Presenter) 패턴은 Model, View, Presenter라는 세 가지 구성 요소로 이루어진 디자인 패턴입니다.

각 구성 요소는 다음과 같은 역할을 담당합니다.

  • Model (모델): 데이터를 저장하고 관리하는 역할을 합니다.
  • View (뷰): 사용자에게 표시되는 UI를 구성합니다.
  • Presenter (프레젠터): View와 Model 사이의 상호 작용을 처리합니다. View로부터 사용자 입력을 받아 Model을 업데이트하고, Model의 변경 사항을 뷰에 반영합니다.

MVC 패턴과 유사하지만, MVP 패턴에서는 Presenter가 View와 Model을 직접 참조하지 않고 인터페이스를 통해 통신한다는 점이 차이점입니다.

이로 인해 코드 결합도가 낮아지고 유연성이 높아집니다.

2. MVP 패턴의 장점

MVP 패턴을 사용하면 다음과 같은 장점을 얻을 수 있습니다.

  • 명확한 역할 분담: Model, View, Presenter 각각의 역할이 명확하게 분리되어 있어 코드를 이해하기 쉽고 유지 관리성이 높아집니다.
  • 단결된 결합: Presenter가 Model과 View를 직접 참조하지 않기 때문에 코드 결합도가 낮아 유연성이 높습니다.
  • 테스트 용이: 각 구성 요소를 별도로 테스트할 수 있어 코드의 품질을 향상시키는 데 도움이 됩니다.
  • 변경 용이: Presenter만 변경하면 View와 Model에 영향을 미치지 않기 때문에 코드 변경이 용이합니다.

3. MVP 패턴의 단점

MVP 패턴을 사용하면 다음과 같은 단점도 존재합니다.

  • 코드 복잡성 증가: MVC 패턴보다 코드가 다소 복잡해질 수 있습니다.
  • 보일러플레이트 코드 증가: Model, View, Presenter 클래스 간의 상호 작용을 처리하는 코드가 필요합니다.
  • 프레젠터 역할 이해 어려움: 처음에는 프레젠터의 역할을 이해하기 어려울 수 있습니다.

4. MVP 패턴 사용 방법

플러터에서 MVP 패턴을 사용하려면 다음 단계를 따릅니다.

 

1. Model, View, Presenter 클래스를 만듭니다.

  • Model 클래스: 데이터를 저장하고 관리하는 역할을 담당합니다.
  • View 클래스: 사용자에게 표시되는 UI를 구성하고 Presenter 클래스의 메서드를 호출합니다.
  • Presenter 클래스: View와 Model 사이의 상호 작용을 처리합니다. View로부터 사용자 입력을 받아 Model을 업데이트하고, Model의 변경 사항을 뷰에 반영합니다.

예제

// Model 클래스
class User {
  String name;
  int age;

  User({required this.name, required this.age});
}

// View 클래스
class UserView extends StatefulWidget {
  @override
  _UserViewState createState() => _UserViewState();
}

class _UserViewState extends State<UserView> {
  late User _user;
  late UserPresenter _presenter;

  @override
  void initState() {
    super.initState();
    _user = User(name: '', age: 0);
    _presenter = UserPresenter(view: this, model: _user);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MVP Pattern Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Name: ${_user.name}'),
            Text('Age: ${_user.age}'),
            RaisedButton(
              child: Text('Update User'),
              onPressed: () {
                _presenter.updateUser('New Name', 30);
              },
            ),
          ],
        ),
      ),
    );
  }
}

// Presenter 클래스
class UserPresenter {
  final UserView _view;
  final User _model;

  UserPresenter({required UserView view, required User model})
      : _view = view,
        _model = model;

  void updateUser(String name, int age) {
    _model.name = name;
    _model.age = age;
    _view.refresh();
  }
}
 

2. Model 클래스에서 데이터를 저장하고 관리하는 메서드를 정의합니다.

 

Model 클래스는 데이터를 저장하고 관리하는 역할을 담당합니다.

필요한 데이터에 따라 다양한 속성과 메서드를 정의할 수 있습니다.

 

예제

// Model 클래스
class User {
  String name;
  int age;

  User({required this.name, required this.age});

  void setName(String name) {
    this.name = name;
  }

  void setAge(int age) {
    this.age = age;
  }
}
 

3. View 클래스에서 UI를 구성하고 Presenter 클래스의 메서드를 호출합니다.

 

View 클래스는 사용자에게 표시되는 UI를 구성하고 Presenter 클래스의 메서드를 호출하여 데이터를 가져오거나 업데이트합니다.

 

예제

// View 클래스
class UserView extends StatefulWidget {
  // ...

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // ...
      body: Center(
        child: Column(
          // ...
          children: <Widget>[
            Text('Name: ${_user.name}'),
            Text('Age: ${_user.age}'),
            RaisedButton(
              child: Text('Update User'),
              onPressed: () {
                _presenter.updateUser('New Name', 30);
              },
            ),
          ],
        ),
      ),
    );
  }
}
 

4. Presenter 클래스에서 Model 클래스의 메서드를 호출하여 데이터를 가져오고, View 클래스의 메서드를 호출하여 UI를 업데이트합니다.

 

Presenter 클래스는 View와 Model 사이의 중개 역할을 수행합니다.

View로부터 사용자 입력을 받아 Model을 업데이트하고, Model의 변경 사항을 뷰에 반영합니다.

 

예제

// Presenter 클래스
class UserPresenter {
  final UserView _view;
  final User _model;

  UserPresenter({required UserView view, required User model})
      : _view = view,
        _model = model;

  void updateUser(String name, int age) {
    _model.setName(name);
    _model.setAge(age);
    _view.refresh(); // View 클래스의 refresh 메서드를 호출하여 UI 업데이트
  }
}

 

5. MVP 패턴 활용을 위한 추가 팁

  • 플러터 패키지 활용: BLoC, Provider, GetX와 같은 플러터 패키지를 활용하여 MVP 패턴을 더욱 효율적으로 구현할 수 있습니다.
  • 테스트 코드 작성: 단위 테스트와 위젯 테스트를 작성하여 코드의 품질을 보장합니다.
  • 코드 리팩토링: 코드를 정기적으로 리팩토링하여 코드의 명확성과 유지 관리성을 유지합니다.

6. MVP 패턴 대안

 

플러터에는 MVP 패턴 외에도 MVC(Model-View-Controller) 패턴, MVVM(Model-View-ViewModel) 패턴과 같은 다양한 아키텍처 패턴이 존재합니다.

프로젝트의 특성에 맞는 적절한 패턴을 선택하는 것이 중요합니다.

 

7. 결론

 

플러터에서 MVP 패턴은 코드를 명확하고 테스트하기 쉽게 만들고, 유지 관리성을 향상시키는 데 도움이 되는 강력한 도구입니다.

하지만, 모든 프로젝트에 적합한 것은 아니므로, 프로젝트의 특성을 고려하여 신중하게 선택해야 합니다.

 

Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

 

 

728x90
반응형