본문 바로가기
비전공자를 위한 Flutter/Flutter 심화과정

How to build Flutter BLoC Pattern Folder Structure 디자인 패턴 폴더 구조 알아보기

by 밍잔 2022. 6. 28.

BLoC이란?

 

BLoC(Business Logic of Component)는 구글에서 비즈니스 로직을 화면 레이어와 분리하여 개발자가 코드를 더 효율적으로 재사용할 수 있게 하기 위해 만든 디자인 패턴입니다. Flutter 앱개발에서 유지보수를 위해 가장 많이 쓰이는 디자인 패턴이죠.

 

 


BLoC의 핵심 컨셉

 

상태관리 라이브러리로 불리우는 Bloc의 핵심 컨셉은 Stream입니다. Stream은 반복가능한 비동기 이벤트들의 정렬인데요. 여러분이 다음 이벤트 정보를 요청하기 전에,다음 이벤트가 준비되면 Stream이 알아서 알려주게끔 되어있습니다. 

 

 

Stream은 이벤트 시퀀스를 받아 제공합니다. 각각의 이벤트는 데이터 이벤트, 에러 이벤트로 이루어져 있습니다. Stream이 모든 이벤트를 송출하면, 하나의 "done"와 함께 끝났다는 이벤트를 리스너에게 알립니다.

 

 

Stream은 여러가지 방법으로 생성되고, 같은 방법으로 사용됩니다. 비동기 반복문 await for로 Stream의 이벤트를 반복하는 거죠.

Stream<int> dataStream() async* {
  for (int i = 0; i <= 10; i++) {
    await Future.delayed(const Duration(seconds: 1));
    yield i;
  }
}

void main() {
  Stream<int> stream = dataStream();

  stream.listen((event) {
    log(event.toString());
  });
}

 

Stream 처리에는 async*, await, yield 3가지 핵심 키워드가 있습니다.

 

async*는 비동기 함수의 생성을 의미합니다. 비동기 데이터를 생성하죠. 비동기 함수 안에서는 yield 키워드를 통해 데이터를 스트림에 전달할 수 있습니다. await 키워드는 다음 단계로 진행하기 전에 현재 처리중인 작업을 기다리는 것을 도와줍니다.

 


BLoC 패턴을 써야하는 이유

 

쉽게 말하면 비즈니스 로직과 UI가 분리되어 있어 변경이 필요한 코드만 수정하면 됩니다. 동료가 만들어 놓은 BLoC 재사용이 가능하죠. 당연한 이야기지만 단일책임원칙을 지켜 네이밍을 잘 한다면 유지보수 하기에도 좋습니다.

 

사용자가 앱과 상호작용할 때마다 변경된 상태를 알릴 필요가 있습니다. 그러려면 앱 화면의 상태를 변화시키는 어떤 이벤트들이 일어나는지 주시하고 있을 필요가 있죠. Bloc은 상태값의 Stream을 송출하고, 이벤트 Stream을 받습니다. 따라서 mapEventToState메소드를 통해 화면 변경이 요구되는 State 변경 처리와 이벤트를 맵핑하여 UI를 실시간으로 리빌드할 수 있습니다. 

 

BlocProvider는 Bloc에 모든 자식을 생성해주고 제공해주는 위젯입니다. 의존성 주입 위젯으로 알려져 있는데요. 하나의 Bloc 인스턴스가 서브트리 안의 여러 위젯으로서 제공될 수 있습니다. 서브트리가 우리가 제공하는 Bloc에 의존하게 된다는 말이죠.

 

오른쪽에 위치한 사진처럼 트리의 중간에 BlocProvider를 초기화하면 하위 위젯들에게만 데이터를 전달할 수 있습니다. 인터랙션에 의해 화면 UI가 변경되어야 하는 위젯들이 트리구조상 멀리 떨어져 있는 경우 InheritedWidget이 아니라 BlocProvider를 통해 필요한 데이터를 직접 전달받아 위젯을 리빌드 할 수 있습니다.

 


BLoC 폴더 구조

 

모바일 앱개발용 BLoC 패키지는 flutter_bloc을 사용하시면 됩니다. 사용법에 대해서는 아래 패키지의 문서를 참고하시기 바랍니다.

 

flutter_bloc | Flutter Package

Flutter Widgets that make it easy to implement the BLoC (Business Logic Component) design pattern. Built to be used with the bloc state management package.

pub.dev

 

BLoC 패턴의 폴더구조는 사람마다 프로젝트마다 각각 다른데요. 제가 사용하는 Flutter BLoC 패턴의 폴더구조는 아래와 같습니다. (장바구니를 예시로 만들었습니다.)

 

├── lib
│   ├── blocs
│   │   └── cart
│   │       ├── cart_bloc.dart
│   │       ├── cart_event.dart
│   │       ├── cart_state.dart
│   │       ├── models
│   │       │   └── cart_item.dart
│   │       ├── repositories
│   │       │   ├── cart_repository.dart
│   │       │   └── cart_repository_ab.dart
│   │       └── views
│   │           ├── screens
│   │           │   └── cart_list_screen.dart
│   │           └── widgets
│   │               └── cart_item_row_widget.dart
│   ├── config
│   │   └── theme.dart
│   ├── main.dart
│   └── utils
│       └── foo.dart

 

  • blocs : BLoC 유닛들을 담는 폴더입니다.
    • cart : 장바구니 BLoC 구현에 필요한 파일을 담는 폴더입니다. 
      • cart_bloc.dart : 비즈니스 로직을 담고 있는 bloc파일로 이벤트 처리와 맵핑된 메소드로 state를 관리합니다.
      • cart_event.dart : 비즈니스 로직의 트리거가 되는 이벤트를 정의합니다.
      • cart_state.dart : 비즈니스 로직에 필요한 데이터를 정의합니다.
      • models : 장바구니에 사용되는 데이터 클래스를 담는 폴더입니다.
        • cart_item.dart : 하나의 장바구니 아이템 데이터 클래스와 필드를 정의합니다.
      • repositories : 외부 API 통신을 담당하는 리포지토리를 담는 폴더입니다.
        • cart_respository_ab.dart : 장바구니 관련 리포지토리 추상화 클래스입니다.
        • cart_repository.dart : 장바구니와 관련된 API 통신을 구현한 리포지토리 파일입니다.
      • views : 장바구니 UI와 관련된 파일을 담는 폴더입니다.
        • screens : 장바구니 화면 위젯을 담는 폴더입니다.
        • widgets : 장바구니 화면에 서브트리로 사용되는 위젯들을 모아놓은 폴더입니다.
    • config : 앱 설정 파일들을 담는 폴더입니다.
      • theme.dart : 테마 정보를 정의합니다.
    • utils : 위젯이 아닌 각종 처리를 돕는 함수를 담는 폴더입니다.

 

 

참고 원문 : https://www.mitrais.com/news-updates/getting-started-with-flutter-bloc-pattern/

댓글