Zpět na domů

Use-cases v BLoC Flutter: refaktoring architektury

Článek popisuje refaktoring BLoC ve Flutter vyjmutím obchodní logiky do use-cases. Uvádějí se příklady kódu před a po, výhody pro testování a škálovatelnost. Přístup je založen na čisté architektuře.

BLoC + use-cases: jak zjednodušit Flutter architekturu
Advertisement 728x90

## Oddělení BLoC a use-cases ve Flutteru: čistá architektura v praxi

BLoC ve Flutteru se často mění v god object: obslužné rutiny událostí míchají volání služeb, validaci a emisi stavů. To ztěžuje údržbu, testování a škálování. Vysunutí obchodní logiky do use-cases obnovuje oddělení vrstev podle principů čisté architektury: presentation (UI a BLoC), domain (use-cases, entity) a data (repositoria, služby).

Use-case implementuje konkrétní scénář: orchestruje služby, zpracovává chyby, aplikuje obchodní pravidla, bez závislosti na UI. BLoC se soustředí na unidirectional flow – přijímá události a emituje stavy.

Klasický BLoC: kde se logika mísí s UI

Typický BLoC volá služby přímo přes DI a provádí side-effects v obslužných rutinách. Příklad zjednodušeného ItemsBloc:

Google AdInline article slot
class ItemsBloc extends Bloc<ItemsEvent, ItemsState> {
  final FetchItemsService _service;

  ItemsBloc(this._service) : super(Initial()) {
    on<FetchItemsEvent>(_onFetchItemsEvent);
  }

  Future<void> _onFetchItemsEvent(FetchItemsEvent event, Emitter<ItemsState> emit) async {
    emit(Loading());
    try {
      final items = await _service.fetchItems();
      emit(Loaded(items: items));
    } catch (error) {
      emit(Error(error: error));
    }
  }
}

Problémy: vysoká propojenost, složité testování, porušení SRP. BLoC zná data, síť a obchodní logiku.

Refaktoring: BLoC jako čistý správce stavů

Po refaktoringu obsahuje BLoC pouze mapování událostí na stavy, bez závislostí:

class ItemsBloc extends Bloc<ItemsEvent, ItemsState> {
  ItemsBloc() : super(Initial()) {
    on<SetLoading>(_onSetLoading);
    on<SetLoaded>(_onSetLoaded);
    on<SetError>(_onSetError);
  }

  Future<void> _onSetLoading(SetLoading event, Emitter<ItemsState> emit) async {
    emit(Loading());
  }

  Future<void> _onSetLoaded(SetLoaded event, Emitter<ItemsState> emit) async {
    emit(Loaded(items: event.items));
  }

  Future<void> _onSetError(SetError event, Emitter<ItemsState> emit) async {
    emit(Error(error: event.error));
  }
}

Use-case přebírá orchestraci:

Google AdInline article slot
class FetchItemsUseCase {
  final ItemsBloc bloc;
  final FetchItemsService service;

  FetchItemsUseCase({required this.bloc, required this.service});

  Future<void> call() async {
    bloc.add(SetLoading());
    try {
      final items = await service.fetchItems();
      bloc.add(SetLoaded(items: items));
    } catch (error) {
      bloc.add(SetError(error: error.toString()));
    }
  }
}

BLoC se zkrátí na 20 řádků, stane se testovatelným: mock událostí a kontrola stavů.

Výhody use-cases jako orchestrátora

Use-case není jen proxy – spojuje data z repozitářů, aplikuje pravidla, loguje, synchronizuje. Závisí na abstrakcích (interfacech), ne na implementacích.

Klíčové výhody:

Google AdInline article slot
  • Testovatelnost: mock služeb/repositorií pro unit testy use-case.
  • Škálovatelnost: nové scénáře se přidávají bez změn BLoC (Open/Closed).
  • Flexibilita DI: služby se injektují do use-case, BLoC je nezávislý.
  • Čitelnost: obchodní scénáře jsou izolované v samostatných třídách.

V reálném projektu refaktoring zkrátil čas vývoje o 30 %, snížil chyby, zjednodušil testy.

Tok dat a kompromisy

UI → use-case → služby/repositoria → události do BLoC → stav UI. Use-case zná BLoC (kompromis čisté architektury pro jednoduchost), ale UI se očistí od bloc.add.

BLoC – unidirectional data flow: předvídatelné chování, snadné testy. Use-cases se testují odděleně: simulace odpovědí, kontrola volání.

Co je důležité

  • Oddělení vrstev: BLoC – správce stavů, use-cases – doménová logika.
  • SRP v praxi: každá třída má jednu odpovědnost.
  • Zjednodušené testování: čisté funkce v BLoC, mocky v use-cases.
  • Škálovatelnost: přístup funguje s Cubit, Riverpod nebo jinými správci stavů.

Přístup je použitelný pro jakýkoli Flutter projekt, kde BLoC roste. Změřte metriky před/po: velikost tříd, pokrytí testů, čas na funkce.

— Editorial Team

Advertisement 728x90

Číst dál