Categories
Geral

O que pastéis podem te ensinar sobre injeção de dependência

Hoje vamos, com pastéis, entender um pouco sobre Injeção de Dependência (Dependency Injection, em inglês)

Eae galera, como estão vocês?! Espero que bem! Esses últimos dias estive bastante atarefado com o trabalho e também decidindo sobre o que eu iria escrever… Eis que a resposta veio de um bate-papo com um “irmão de código” no Slack do Brasil .NET sobre Injeção de Dependência e eu pude perceber que este seria um ótimo assunto para escrever… Ou não (rs)…

Pode ser que você não esteja dando “muita bola” para o assunto, mas te digo, é importante, EXTREMAMENTE IMPORTANTE, pois esse conceito é uma das bases para implementações de Patterns como DDD, é AMPLAMENTE UTILIZADO no desenvolvimento de aplicativos com Xamarin (e outras tecnologias também), e por aí vai.

Mas, Pastéis?!

Por definição, “Injeção de dependência é um padrão de desenvolvimento de programas de computadores utilizado quando é necessário manter baixo o nível de acoplamento entre diferentes módulos de um sistema. Nesta solução as dependências entre os módulos não são definidas programaticamente, mas sim pela configuração de uma infraestrutura de software (container) que é responsável por “injetar” em cada componente suas dependências declaradas.” (by Wikipédia).

Fácil? Mais ou menos né!

É aqui que entram os pastéis (rs)… Normalmente, uma pastelaria funciona da seguinte forma, supondo que seja uma pastelaria que prepara o pastel na hora:

O cliente escolhe um determinado recheio, o pasteleiro pega uma fração da massa (pré-preparada), recheia o pastel, fecha a masssa envolvendo o recheio dando forma ao pastel, “joga” no óleo quente pra fritar e daqui algum tempinho o pastel tá pronto… Mais ou menos como alguns clientes algumas pessoas pensam que funciona o processo de desenvolvimento de software (rs)…

Agora, imagine que uma pastelaria, arrumou uma forma de pegar a massa sem recheio, fechar, dar a forma do pastel, jogar no óleo e, só depois, o cliente escolheria o recheio que seria “injetado” no pastel! Fantástico!!!

O exemplo pode ter sido descabido, até esdrúxulo, mas imaginar como isso funcionaria é um exercício interessante (ou no mínimo engraçado, rs…), para ilustrar como funciona a Injeção de Dependência.

Então vamos agora entender como as coisas se relacionam…

Fritando o pastel…

Supondo que estamos desenvolvendo um aplicativo mobile, usando Xamarin Forms, e nosso aplicativo vai utilizar o banco de dados SQLite.

Enfim, mãos na massa (rs, não pude evitar)!

  1. Abra o Visual Studio
  2. Clique em File->New->Project
  3. Na janela “New Project”, do lado esquerdo, selecione a categoria Cross-Platform, em seguida, do lado direito, selecione o template “Blank App (Xamarin.Forms Portable)”, conforme imagem abaixo, dê um nome ao seu projeto, no meu caso vou usar “Balivo.DISampleApp” e em seguida clique em “Ok”.

Criamos nossa “Solution” e agora vamos implementar nossa camada de acesso compartilhada.

Clique com o botão direito do mouse sobre o seu projeto “Core” do aplicativo, no meu caso é o projeto “Balivo.DISampleApp”, e clique em “Add->New Folder” (como mostra a imagem abaixo), e dê o nome de “Data” a esta nova pasta.

Clique com o botão direito do mouse novamente sobre o seu projeto “Core” do aplicativo, clique em “Add->New Folder” (como exibido acima), e dê o nome de “Providers” a esta nova pasta.

Na pasta “Data”, nós vamos colocar as classes relacionadas a nossa camada de acesso a dados. Já na pasta “Providers” serão colocadas interfaces que irão descrever como serão os “recheios dos nossos pastéis”.

Antes de implementarmos nosso projeto exemplo, precisamos instalar um NuGet Package para trabalharmos com o SQLite.

Clique com o botão direito do mouse sobre “References” (ainda no projeto “Core”), clique em “Manage NuGet Packages” em seguida clique na guia “Browse” e procure pelo pacote “SQLite.Net-PCL” (veja imagem abaixo) e instale o pacote.

Agora que instalamos o SQLite em nosso projeto “Core”, clique com o botão direito do mouse na pasta “Data”, clique em “Add->Class” (como mostra a imagem abaixo)

Dê o nome de “Cidade” a esta classe, e implemente-a da seguinte forma:

using SQLite.Net.Attributes;
using System;

namespace Balivo.DISampleApp.Data
{
    public sealed class Cidade
    {
        [PrimaryKey]
        public Guid CidadeId { get; set; }
        public string Nome { get; set; }
        public string UF { get; set; }
    }
}

Esta classe irá representar a tabela “Cidade” em nosso banco de dados (Não pretendo me alongar com isso e nem implementar um exemplo de alta complexidade, não é o objetivo deste artigo).

Agora, clique com o botão direito do mouse na pasta “Data”, clique em “Add->New Item” (+/- como na imagem acima, selecionando outra opção), na janela “Add New Item”, selecione “Interface”, dê o nome de “ISQLiteConnectionProvider” a essa interface e clique em “Ok”. Implemente da seguinte forma:

using SQLite.Net;

namespace Balivo.DISampleApp.Providers
{
    public interface ISQLiteConnectionProvider
    {
        SQLiteConnection GetConnection();
    }
}

Para que a injeção de dependência funcione, TODAS as “camadas” que utilizam uma parte que será injetada, devem conhecer as características dessa parte, e também o objeto concreto deverá RESPEITAR TODAS AS CARACTERÍSITCAS conhecidas pelas demais camadas. Para isso usamos uma “Interface”.

Uma interface tem como característica definir um “contrato” onde todas as regras devem ser respeitadas, em outras palavras, se uma interface declara um método, este método deverá ser implementado pela classe que herda a interface, o mesmo ocorre com propriedades em um interface.

Interfaces, diferentemente de classes abstratas, não possuem implementações de métodos, apenas seus “cabeçalhos”.

Continuando… Clique com o botão direito do mouse na pasta “Data” novamente e clique em “Add->Class”, e dê o nome de “MobileDatabase” a essa classe e implemente da seguinte forma:

using Balivo.DISampleApp.Providers;
using SQLite.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace Balivo.DISampleApp.Data
{
    sealed class MobileDatabase
    {
        private static readonly Lazy<MobileDatabase> _lazy = new Lazy<MobileDatabase>(() => new MobileDatabase());

        public static MobileDatabase Current { get { return _lazy.Value; } }

        private readonly SQLiteConnection _Db;

        public MobileDatabase()
        {
            this._Db = DependencyService.Get<ISQLiteConnectionProvider>().GetConnection();
            this._Db.CreateTable<Cidade>();
        }

        public Task<int> CidadeSave(Cidade pCidade)
        {
            pCidade.UF.ToUpper();

            return Task.Factory.StartNew(() =>
            {
                return this._Db.InsertOrReplace(pCidade);
            });
        }

        public Task<List<Cidade>> CidadeGetAll()
        {
            return Task.Factory.StartNew(() =>
            {
                return this._Db.Table<Cidade>().ToList();
            });
        }

        public Task<List<Cidade>> CidadeGetByUF(string pUF)
        {
            return Task.Factory.StartNew(() =>
            {
                return this._Db.Table<Cidade>().Where(lbda => lbda.UF.Equals(pUF.ToUpper())).ToList();
            });
        }
    }
}

Fazendo uma analogia com o exemplo do pastel, esta classe é a “massa” fechada do nosso pastel. Porquê? É ela que está sendo “recheada” com o que será “injetado” pelo serviço de injeção de dependência.

Observe a linha 21 do código acima, estamos atribuindo a variável local “this._Db” uma conexão com o banco de dados SQLite, que é iniciada pela classe que implementa a interface “ISQLiteConnectionProvider”.

Note que esta classe não é instanciada de forma “normal”, ela é “solicitada” através do mecanismo de injeção de dependência, que neste caso estamos utilizando o do próprio Xamarin Forms, em:

DependencyService.Get().

“DependencyService” é o serviço de injeção de dependência do Xamarin Forms e não requer configurações muito complexas, é só (praticamente) usar.

Neste ponto não vou prosseguir com a criação da tela do aplicativo, view models, comandos, etc… Tudo isso pode ser visto no repositório do aplicativo através deste link.

Vamos agora criar o “recheio” do nosso “pastel”.

Adicione uma nova pasta, desta vez no projeto “Droid”, e dê o nome de “Providers” a esta pasta.

Adicione uma nova classe a pasta “Providers”, a esta nova classe, dê o nome de “AndroidSQLiteConnectionProvider” e implemente conforme segue:

using Balivo.DISampleApp.Droid.Providers;
using Balivo.DISampleApp.Providers;
using System.Runtime.CompilerServices;
using SQLite.Net;
using System;
using SQLite.Net.Platform.XamarinAndroid;
using System.IO;

[assembly: Dependency(typeof(AndroidSQLiteConnectionProvider))]

namespace Balivo.DISampleApp.Droid.Providers
{
    sealed class AndroidSQLiteConnectionProvider : ISQLiteConnectionProvider
    {
        public AndroidSQLiteConnectionProvider()
        {

        }

        public SQLiteConnection GetConnection()
        {
            return new SQLiteConnection(new SQLitePlatformAndroid(), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "DISampleDatabase.db3"));
        }
    }
}

A classe que acabamos de implementar será injetada na classe “MobileDatabase” que está em nosso projeto “Core” quando o método “Get” do serviço de dependência for chamado.

O serviço de injeção de dependência irá criar uma instância da classe “AndroidSQLiteConnectionProvider” e isso é configurado na linha 9 da classe que acabamos de implementar acima.

Na linha:

[assembly: Dependency(typeof(AndroidSQLiteConnectionProvider))]

É dessa forma que configuramos o serviço de injeção de dependência do Xamarin.Forms.

Cada “framework” ou serviço de DI (sigla de Injeção de Dependência, em inglês) tem sua forma de configuração, alguns permitem utilizar Singleton e muitas outras funcionacidades interessantes.

Enfim, com isso entendemos basicamente como utilizamos injeção de dependência em nossos projetos Xamarin e como funciona esta técnica muito útil no desenvolvimento de projetos com Patterns “modernos”.

Concluindo…

Injeção de Dependência tem como objetivo oferecer uma estrutura de baixo acomplamento e isso resulta em reusabilidade de código, facilidade de manutenção, criação de códigos extremamente testáveis e torna o código mais compreensível.

Outro aspecto interessante, dentro do mesmo assunto, é IoC (Inversão de Controle). Importante lembrar que IoC não é a MESMA COISA que DI. Para ser mais exato podemos dizer que conseguimos Inverter o Controle utilizando Injeção de Dependência.

Um último detalhe é que no SOLID, estamos falando da letra “D”, de “DIP” ou “The Dependency Inversion Principle” (Princípio da inversão de dependência) que diz: Dependa de uma abstração e não de uma implementação. Quem sabe assunto para um próximo artigo… Quem sabe…

Como sempre (que dá), o código está disponível no GitHub e pode ser acessar NESTE LINK.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *