Flutter - Injeção de dependência - I
Hoje veremos o conceito de injeção de dependência(ID) no Flutter e as abordagens para usar este recurso e obter um baixo acoplamento. |
|
O que é o Flutter ?
O Flutter é um SDK de aplicativo móvel do Google que ajuda a criar aplicativos móveis modernos para iOS e Android usando uma única (quase) base de código.
Se você não conhece o Flutter veja o meu artigo : Flutter - Primeiros contatos e impressões
Injeção de dependência no Flutter
Neste artigo vamos tratar das 3 formas mais usadas para realizar a injeção de dependência no Flutter :
A injeção de dependência(DI) é um padrão de projeto cujo objetivo é manter um baixo acoplamento entre diferentes módulos de um sistema. Assim ao realizar a injeção de dependência estamos fornecendo aos objetos do nosso sistema outros objetos dos quais eles dependem com baixo acoplamento.
Nota: Uma forma de aplicar a Injeção de Dependência é definir uma configuração usando um framework ou programa (container) que fica responsável por "injetar" em cada componente suas dependências declaradas.
Veja esse código:
class LoginService {
Api api;
}
|
Aqui vemos que LoginService depende do objeto api ou seja depende da classe Api.
A forma mais usual de obter essa dependência em uma classe é através do seu construtor injetando a instância no construtor:
class LoginService {
Api api;
// Injeta a api no construtor
LoginService(this.api);
}
|
Agora vamos pensar em termos de Widgets no Flutter. Considere um simples Statelesswidget que dependa de uma instância de uma classe Produto.
Podemos, da mesma forma injetar essa instância no construtor do widget:
import 'package:flutter/material.dart';
import 'model/produto.dart';
class HomePage extends StatelessWidget {
final Produto produto;
HomePage(this.produto)
@override
Widget build(BuildContext context) {
return Container(
);
}
}
|
Então tudo certo !!!!
Calma, no Flutter o problema é um pouco mais complexo...
Devemos lembrar que no Flutter tudo são Widgets, e que as aplicações são construidas usando árvores de widgets onde temos uma hierarquia de diversos níveis de widgets.
Assim, passar dependências através de um construtor é perfeitamente adequado para acessar dados um nível abaixo, talvez até dois níveis.
E se você tiver quatro níveis na árvore de widgets e precisar dos dados de um objeto no seu código ?
Agora imagine que todos esses widgets são widgets em arquivos separados com sua própria lógica:
Complicou ,
não é mesmo !!!!
Agora se você quiser passar o Produto para o
MeuText para exibir a informações do
produto, seria necessário criar e adicionar o
construtor e manter a variável de membro local apenas para passar para o
próximo construtor do widget.
Imagine agora, e se você trocar o widget MeuText por um outro widget de pai diferente. Você precisaria remover todo o código desnecessário e adicioná-lo a todos os novos pais dos widgets que exigem seus dados.
Deu para
sentir o drama ???
É por isso que usamos a injeção de dependência, para garantir que se os dados
forem necessários em qualquer lugar da árvore de widgets, por qualquer widget,
poderemos recuperá-los facilmente.
Vamos começar com o InheritedWidget.
1- Injeção de dependência com InheritedWidget
A classe InheritedWidget é uma classe Base para widgets que propagam informações com eficiência na árvore de widgets.
De forma bem simples, um widget herdado permite efetivamente fornecer acesso, através do BuildContext, a todas as suas propriedades, a todos os widgets da subárvore.
É muito comum no Flutter e é usado para o Theme, MediaQueries e tudo o mais que o aplicativo base fornece.
Se você já usou o Flutter antes, provavelmente já encontrou o método 'of' em diferentes classes aqui e ali, em um código parecido com esse abaixo:
Theme.of (context) .textTheme
MediaQuery.of (context) .size
|
Esses widgets (Theme, MediaQuery) são widgets herdados. Em praticamente qualquer lugar do seu aplicativo, você pode acessar o seu tema, porque ele é herdado.
A seguir temos um esqueleto de um InheritedWidget chamado MeuWidget:
class MeuWidget extends InheritedWidget {
MeuWidget({Key key, this.child}) : super(key: key, child: child);
final Widget child; static MeuWidget of(BuildContext context) { return (context.inheritFromWidgetOfExactType(MeuWidget)as MeuWidget); } @override
bool updateShouldNotify( MeuWidget oldWidget) {
return true;
}
}
|
Nota: Para criar o código acima no VS Code instale a extensão Awesome Flutter Snippets e digite : inheritedW
Agora vamos adicionar a referência ao nosso Produto como uma propriedade no Widget. Manteremos uma instância final de longa duração e a retornaremos por meio de um getter :
class MeuWidget extends InheritedWidget {
MeuWidget({Key key, this.child}) : super(key: key, child: child); final Widget child;
final Produto _produto = Produto(); Produto get produto => _produto; static MeuWidget of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(MeuWidget)as MeuWidget);
}
@override
bool updateShouldNotify( MeuWidget oldWidget) {
return true;
}
}
|
Pronto ! já temos um widget herdado.
Agora vejamos como usar o widget MeuWidget que é herda de InheritedWidget.
A maneira como os widgets herdados são usados é envolvendo a árvore que você deseja no widget herdado.
Se quisermos que esse widget seja fornecido a todo o nosso aplicativo, basta envolver o MaterialApp com o widget MeuWidget.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MeuWidget(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeView()),
);
}
}
|
Simples...
Agora como podemos acessar o nosso widget MeuWidget ?
A forma como acessamos o widget herdado em nosso código é usando a chamada .of e passando o contexto. Podemos atualizar nosso widget HomePage e remover o Produto passado pelo construtor, bem como a variável de classe que mantivemos.
Agora podemos fazer com que nosso HomePage fique assim :
import 'package:flutter/material.dart';
import 'model/produto.dart';
class HomePage extends StatelessWidget {
HomePage()
@override
Widget build(BuildContext context) {
return Container(
);
}
}
|
Assim, em
qualquer lugar do aplicativo em que você deseja usar o objeto
Produto, tudo o que você fará é declarar:
var produto = MeuWidget.of (context).produto;
Maravilha...
A favor desta abordagem temos que ela força um fluxo de dados direcional e usa a abordagem de construção do Flutter.
Como desvantagem temos que ela é um tanto verbosa (muito
código) e além disso qualquer widget descendente de InheritedWidget deve ser
imutável, o que significa que você não pode alterar seus dados, mas deve criar
uma nova instância com novos dados. Para poder fazer isso dentro da árvore de
widgets, você sempre precisa envolvê-lo em um
StatefulWidget.
Outro fator importante é que se um InheritedWidget
sofrer uma alteração, não somente os Widgets que fazem referência a ele serão
atualizados, mas o contexto circundante, oque significa que esse contexto
completo, incluindo todos os seus filhos, será reconstruído. Ou seja, se você
colocar o seu widget herdado na base da sua árvore, ele reconstruirá a árvore
inteira.
Para minimizar esse trabalho de reconstrução você teria que adicionar diferentes widgets herdados em diferentes locais da sua árvore.
Na próxima parte do artigo veremos a injeção de dependência usando o get_it.
"Porque
Deus não nos destinou para a ira, mas para a aquisição da salvação, por nosso
Senhor Jesus Cristo,
Que morreu por nós, para que, quer vigiemos, quer durmamos, vivamos juntamente
com ele."
1 Tessalonicenses
5:9,10
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Super DVD C# - Recursos de aprendizagens e vídeo aulas para C#
Curso Fundamentos da Programação Orientada a Objetos com VB .NET
Flutter - Apresentando o widget MaterialApp - Macoratti
Flutter - Apresentando Flutter Studio - Macoratti
Flutter - Lista Básica - Macoratti
Flutter - Apresentando Widgets - Macoratti
Flutter - Obtendo dados da Web - Macoratti