Flutter BLoC (Business Logic Component) 패턴은 애플리케이션의 비즈니스 로직을 UI와 분리하여 관리하기 위한 패턴입니다. 이는 상태 관리를 보다 체계적으로 할 수 있게 해주며, 테스트 가능성과 유지보수성을 높여줍니다. BLoC 패턴은 Flutter 애플리케이션에서 많이 사용되는 상태 관리 패턴 중 하나입니다. 여기서는 BLoC 패턴의 주요 개념과 구현 방법을 상세히 설명하겠습니다.
주요 개념
- BLoC (Business Logic Component):
- 비즈니스 로직을 포함하는 클래스입니다.
- 입력(Event)과 출력(State)으로 구성됩니다.
- 스트림을 통해 상태 변경을 알립니다.
- Event:
- 사용자의 입력이나 애플리케이션에서 발생하는 이벤트를 의미합니다.
- BLoC에 전달되어 상태 변화를 유도합니다.
- State:
- BLoC의 상태를 나타냅니다.
- 이벤트에 따라 상태가 변경됩니다.
BLoC 패턴의 구조
- Event 클래스:
- 추상 클래스로 정의하고, 다양한 이벤트에 대해 상속하여 구현합니다.
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
- State 클래스:
- 추상 클래스로 정의하고, 다양한 상태에 대해 상속하여 구현합니다.
abstract class CounterState {}
class CounterInitial extends CounterState {
final int count;
CounterInitial(this.count);
}
class CounterUpdated extends CounterState {
final int count;
CounterUpdated(this.count);
}
- BLoC 클래스:
Bloc
클래스를 상속하고, 이벤트와 상태를 제네릭 타입으로 지정합니다.- 이벤트를 받아 상태를 출력하는
mapEventToState
메소드를 구현합니다.
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterInitial(0));
@override
Stream<CounterState> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield CounterUpdated((state as CounterInitial).count + 1);
} else if (event is Decrement) {
yield CounterUpdated((state as CounterInitial).count - 1);
}
}
}
- UI 연결:
BlocProvider
를 사용하여 BLoC를 제공하고,BlocBuilder
를 사용하여 상태 변화를 감지합니다.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterPage(),
),
);
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
int count = (state is CounterInitial) ? state.count : (state as CounterUpdated).count;
return Center(child: Text('Count: $count'));
},
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () => counterBloc.add(Increment()),
child: Icon(Icons.add),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: () => counterBloc.add(Decrement()),
child: Icon(Icons.remove),
),
],
),
);
}
}
장점
- 비즈니스 로직의 재사용성: 비즈니스 로직을 UI와 분리하여 다른 UI 컴포넌트에서도 재사용할 수 있습니다.
- 테스트 용이성: 비즈니스 로직이 분리되어 있어 유닛 테스트가 용이합니다.
- 유지보수성: 코드의 분리가 명확하여 유지보수가 용이합니다.
단점
- 복잡성 증가: 작은 애플리케이션에서는 다소 과도한 구조일 수 있습니다.
- 학습 곡선: 패턴의 이해와 구현에 시간이 걸릴 수 있습니다.
BLoC 패턴은 대규모 애플리케이션에서 특히 유용하며, 상태 관리와 비즈니스 로직을 깔끔하게 분리할 수 있습니다. 위의 예제를 바탕으로 다양한 애플리케이션에 BLoC 패턴을 적용해보세요.