triple 0.0.15 copy "triple: ^0.0.15" to clipboard
triple: ^0.0.15 copied to clipboard

outdated

abstraction for the Segmented State Pattern

Triple #

Este package é uma abstração do Segmented State Pattern( Padrão de Estado Segmentado) que impõem barreiras arquiteturais para reatividades individuais.

Essa abstração server para a crição de implementações do SSP usando qualquer objeto Reativo como base para criar uma Store(Objeto Responsável pela Lógica do Estado de um componente).

Como criar uma Store? #

.

Triple

Seguindo o SSP, nossa Store precisa segmentar os dados do estado em 3 vias, um State(contendo o valor do Estado), um Error(Contendo o objeto de exception do estado) e o Loading(indicando se o valor do estado está sendo carregado). Essas 3 propriedades fazem parte do objeto Triple que é herdado como propriedade na classe abastrata Store. Vamos entao ver passo-a-passo como criar um Store baseado em qualquer sistema de Reatividade existente.

PASSO 1: Escolha uma forma de Reatividade. #

O SSP não coloca nenhum requerimento sobre o tipo de reatividade que poderá ser utilizada no padrão, então o desenvolvedor deve escolher a que mais lhe agrada para criar uma Store. Alguns exemplos de ferramentas:

  • Streams
  • ValueNotifier/ChangeNotifier
  • MobX

Para os próximos passos usaremos "Streams", mas fique a vontade sobre essa escolha.

PASSO 2: Crie uma classe que herde de Store #

Como já falamos, um objeto Store serve para armazenar a Lógica de Estado de um componente.

abstract class StreamStore extends Store {}

Também é prudente colocar "tipos genéricos" para o "state" e "error", faremos isso no StreamStore e depois reatribuiremos na Store.

IMPORTANTE: Herde os tipos genéricos de Object para impedir o uso de dynamics.

e assim temos:

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error> {}

Precisamos ainda declarar o construtor da classe pai com um valor inicial do state e assim concluimos essa etapa:

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error> {

  StreamStore(State state) : super(state);

}

PASSO 3: Inicie um objeto com a reatividade escolhida. #

Inclua de forma privada uma propriedade reativa que trabalhe com o tipo Triple<State, Error>():

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error> {

  //main stream
  final _tripleController = StreamController<Triple<State, Error>>.broadcast(sync: true);

  StreamStore(State state) : super(state);

}

PASSO 4: Encerre o objeto reativo #

Sobrescreva o método destroy que será chamado quando a Store for descartada.

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error> {

  //main stream
  final _tripleController = StreamController<Triple<State, Error>>.broadcast(sync: true);

  StreamStore(State state) : super(state);

  @override
  Future destory() async {
    await _tripleController.dispose();
  }

}

PASSO 5: Sobrescreva o método de Propagação. #

Quando o Store decide propagar um valor do tipo Triple, ele o faz chamando o método propagate(). Sobreescreva esse método para direcionar o fluxo para o seu controle principal de reatividade.

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error> {

  //main stream
  final _tripleController = StreamController<Triple<State, Error>>.broadcast(sync: true);

  StreamStore(State state) : super(state);

  @protected
  @override
  void propagate(Triple<State, Error> triple){
    _tripleController.add(triple);
  }

  @override
  Future destory() async {
    await _tripleController.dispose();
  }

}

IMPORTANTE: O método propagate está assinado com @protected porque ele só deve ser usado dentro da classe StreamStore.

PASSO 6: Sobreescreva o método observer #

Esse método é chamado para escutar os eventos segmentados do estado(state, error e loading). Sobreescreva chamando as funções de cada segmento.

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error> {

  //main stream
  final _tripleController = StreamController<Triple<State, Error>>.broadcast(sync: true);

  StreamStore(State state) : super(state);

  @protected
  @override
  void propagate(Triple<State, Error> triple){
    _tripleController.add(triple);
  }

  @override
  Disposer observer({
    void Function(State state)? onState,
    void Function(Error error)? onError,
    void Function(bool loading)? onLoading,
  }){
    final _sub = _tripleController.listen((triple){
      if(triple.event == TripleEvent.state){
        onState(triple.state);
      } else if(triple.event == TripleEvent.error){
        onError(triple.error);
      } else if(triple.event == TripleEvent.loading){
        onLoading(triple.loading);
      }
    });
    return () async {
      await _sub.cancel();
    }
  }

  @override
  Future destory() async {
    await _tripleController.dispose();
  }

}

PASSO 7 (OPCIONAL): Defina Seletores #

Pode ser interessande ter seletores de quada segmento do estado de forma reativa. Isso é um State, Error e loading reativo. Se dejesa ter essa possibilidade no Store implemente a interface Selectors:

abstract class StreamStore<State extends Object, Error extends Object> extends Store<State, Error>
implements Selectors<Stream<State>, Stream<Error>, Stream<bool>>
 {

  //main stream
  final _tripleController = StreamController<Triple<State, Error>>.broadcast(sync: true);

  @override
  late final Stream<State> selectState = _tripleController.stream
      .where((triple) => triple.event == TripleEvent.state)
      .map((triple) => triple.state);

  @override
  late final Stream<Error> selectError = _tripleController.stream
      .where((triple) => triple.event == TripleEvent.error)
      .where((triple) => triple.error != null)
      .map((triple) => triple.error!);

  @override
  late final Stream<bool> selectLoading = _tripleController.stream
      .where((triple) => triple.event == TripleEvent.loading)
      .map((triple) => triple.loading);

  StreamStore(State state) : super(state);

  ...

Usando o Padrão Memento com o MementoMixin #

Você pode adicionar Desfazer ou refazer um estado usando o Memento Pattern. Isso significa que poderá retornar ao estado anterior usando o método undo() e também prosseguir com o método redo().


class Counter extends StreamStore<int, Exception> with MementoMixin {}

Exemplos #

Features and bugs #

Please file feature requests and bugs at the issue tracker.

55
likes
0
pub points
74%
popularity

Publisher

verified publisherflutterando.com.br

abstraction for the Segmented State Pattern

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

meta

More

Packages that depend on triple