VB .NET - Criando uma aplicação em camadas


Lá vou eu em mais um artigo sobre como criar uma aplicação em camadas, no nosso exemplo em 3 camadas. Parece que eu não me canso do assunto não é mesmo ???

E parece que apesar de todo material existente sobre este assunto as dúvidas persistem, principalmente para quem esta iniciando.

Então este artigo é dirigido aos iniciantes e por isso eu vou usar uma linguagem bem simples em um exemplo bem simples usando figuras para ilustrar os conceitos.

Vamos começar definindo o que será preciso para acompanhar o artigo:

  1. Alguns conceitos de programação orientada a objetos : objeto, classe, herança, etc.;
  2. Possuir o Visual Basic 2010 Express Edition que é uma versão grátis e que todos podem usar;
  3. Possuir o banco de dados SQL Server 2008 Express Edition que também é grátis;
  4. Possuir um pouco de paciência para ler o artigo até o fim...

Começando pelo começo...

O significa criar uma aplicação em camadas ?

Quando você acessa a página do seu banco na internet esta usando uma aplicação que possui uma tela de apresentação onde você, usuário, recebe e entra com as informações.

- Quando você faz o login na sua conta acessando a página do seu banco na internet existe uma interface onde você informa seu login e senha.
- Quando você submete esta informação a aplicação aplica as regras de negócios para verificar se seu login e senha são válidos.
- Para isso ele consulta um cadastro de informações, que esta em um banco de dados, e verifica se o que o usuário digitou corresponde ao que esta no cadastro;

Com esse exemplo bem simples podemos perceber que temos 3 partes distintas atuando:

  1. A interface representada pela tela de login solicitando login e senha;
  2. As regras de validação que serão aplicadas representando as regras de negócio;
  3. As informações armazenadas no cadastro representando o banco de dados;

A figura abaixo procura mostrar de forma resumida esses 3 componentes identificando e nomeando cada um deles;

Podemo identificar as seguintes camadas:
  • Camada de Apresentação (Presentation Tier)
  • Camada de Negócios (Business Logic Tier)
  • Camada de Acesso a dados (Data Tier)

Embora para o cliente tudo seja apenas uma única aplicação para o desenvolvedor (você), criar uma aplicação em camadas significa desenvolver separadamente cada um dos componentes identificados no exemplo acima de forma a facilitar a manutenção e ganhar produtividade.

Chama-se a isso uma aplicação com arquitetura em 3 camadas. (Podemos ter aplicações em n-camadas)

Resumindo:

A arquitetura em 3 camadas é uma arquitetura cliente servidor na qual a interface do usuário, processos de negócios e armazenamento de dados são desenvolvidos e mantidos em módulos independentes, ou em plataforma separadas.

Basicamente existem 3 camadas :
- Camada de apresentação - User Interface (UI)
- Camada de Negócios - Business Logic Layer (BLL)
- Camada de Acesso a dados - Data Access Layer (DAL)

Cada camada pode ser desenvolvida e testada separadamente.

Ao realizar a separação das camadas de uma aplicação podemos fazer uma separação física ou uma separação lógica das camadas:

Na figura abaixo vemos um exemplo de projeto usando a física e outro usando a separação lógica das camadas:

Exemplo de projeto com arquitetura em 3 camadas usando a separação física das camadas.

Temos 3 projetos distintos em uma solução.

Exemplo de projeto com arquitetura em 3 camadas usando a separação lógica das camadas.

Temos 1 projeto contendo 3 pastas onde estão os componentes de cada camada em uma solução.

Podemos também ter as classes representando cada camada juntas no projeto:

Quais são os componentes de cada camada ?

De forma bem simples geralmente temos:

1 - Camada de Apresentação (Presentation Tier ou UI)

- Formulários e Controles de Usuário
- Web Forms, Windows Forms, Mobile

2 - Camada de Negócios (Business Tier) (BLL)

- Classes - Regras de Negócio, Objetos de negócio
- VO - Value Objects (Ex: Produto, Cliente, etc.)

3- Camada de Acesso a Dados (DAL)

- Classes - Regras de Acesso a dados, métodos, etc.

Nota: Cabe aqui um esclarecimento para que não haja confusão na utilização dos termos Tier e Layer. Em geral podemos traduzir tais termos como camadas, mas o termo Tier refere-se a camada física enquanto que o termo Layer refere-se a camada lógica.

Criando uma aplicação em 3 camadas na prática

Para que fique bem claro toda a teoria vamos criar uma aplicação em 3 camadas usando a linguagem VB .NET.

Como o artigo é para iniciantes eu vou simplificar ao máximo para que o entendimento não seja prejudicado.

Vamos criar uma aplicação para acessar e dar manutenção em cadastro de alunos armazenado na tabela Clientes do banco de dados Microsoft Access Cadastro.mdb.

Obs: Escolhi um banco de dados Microsoft Access por ser mais simples de trabalhar e distribuir mas em aplicações comerciais aconselha-se usar um verdadeiro RDMS como SQL Server, MySQL, Oracle, DB2, etc.

Vamos adotar a arquitetura em 3 camadas usando a separação lógica onde teremos a seguinte estrutura:

Abra o Visual Basic 2010 Express Edition e no menu File clique em New Project e selecione o template Windows Forms Application e informe o nome : ProjetoTresCamadas-SeparacaoLogica;

Será criado um projeto contendo um formulário form1.vb. Selecione o formulário form1.vb e altere o seu nome para Camada1_frmApresentacao;

No menu Project clique em Add Class e selecione o template Class informando o nome Camada2_Negocio;

No menu Project clique em Add Class e selecione o template Class informando o nome Camada3_AcessoDados;

Ao final você deverá ver na janela Solution Explorer uma solução contendo um projeto com a seguinte estrutura:

O fluxo da informação entre as camadas é mostrada na figura a seguir:

Vemos que a camada de apresentação (UI) chama a camada de Negócios (BLL) que chama a camada de Acesso a dados (DAL) que acessa o banco de dados e retorna a informação.

Definindo o código da camada de acesso aos dados - DAL

A camada de acesso a dados é uma classe que terá como responsabilidade acessar o banco de dados Cadastro.mdb e realizar operações de consulta e persistência como alterar, incluir e excluir registros. Essas operações são conhecidas como CRUD - Create, Retrieve, Update e Delete.

CRUD (acrônimo de Create, Retrieve, Update e Delete em língua Inglesa) para as quatro operações básicas utilizadas em bancos de dados relacionais(RDBMS) ou em interface para usuários para criação, consulta, atualização e destruição de dados.

Outros acrônimos podem ser usadas para definir as mesmas operações:

  • ABCD: Add, Browse, Change e Delete
  • BREAD: Browse, Read, Edit, Add e Delete
  • VADE(R): View, Add, Delete, Edit (e Restore, para sistemas com processos transacionais)
    http://pt.wikipedia.org/wiki/CRUD

Temos muitas opções para definir o código da camada de acesso a dados, podemos usar DataSets tipados, LINQ to SQL, Entity Framework, NHibernate, etc., mas para quem esta iniciando é bom começar pela então vamos usar ADO .NET.

A ADO.NET consiste em um conjunto de classes definidas pela plata forma .NET framework que podem ser utilizadas para acessar e persistir dados em um banco de dados relacional.

A primeira coisa a fazer para criar uma conexão ADO.NET com uma fonte de dados é escolher o provedor dados .NET . Cada provedor fornece classes que permitem realizar as seguintes tarefas :

O que é um provedor dados .NET ( .NET data providers ) ?

Os provedores de dados .NET são um conjunto de componentes incluídos na arquitetura ADO.NET que permitem a comunicação entre a fonte de dados e o componente , um XML , WEB Service ou uma aplicação.

Quais os tipos de provedores de dados disponíveis ?

Os principais provedores de dados disponíveis com o .NET Framework atualmente são :

Em nosso exemplo vamos usar o provedor OLE DB .NET Data Provider.

O provedor de dados OLE DB .NET utiliza o OLE DB nativo e a interoperabilidade COM para realizar a conexão e a comunicação com uma fonte de dados. Você vai ter que usar um provedor OLE DB ao utilizar este provedor , indicando-o em uma string de conexão.

Ex: "Provider=Microsoft.Jet.OLEB.4.0;Data Source=Banco_Dados.mdb"

Vamos abrir o arquivo Camada3_AcessoDados.vb e iniciar com a declaração do namespace para acessar o banco de dados Microsoft Access:

Imports System.Data.OleDb

A seguir , logo a após a declaração da classe vamos definir a variável cnn que será usada para tratar a conexão com o banco de dados:

Private cnn As OleDbConnection

Devemos declarar também a string de conexão definindo o provedor , o caminho e o nome do banco de dados:

Dim strConexao As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\dados\Cadastro.mdb;"

Em seguida vamos criar uma função chamada getAlunos() que vai receber como parâmetro uma string e que vai devolver um objeto DataTable.

As Funções ou Function - são rotinas que realizam tarefas e que retornam valores.
 

No caso das funções usamos a palavra-chave : Function seguida do nome da função e da relação dos parâmetros e terminamos com a palavra-chave : End Function.
 

No código da função usamos também a palavra-chave : Return que irá retornar o valor da função. Assim temos:

Sub NomedaFunçõa (parametro1 As TipodoParametro1, Parametro2 As TipodoParametro1, ...)

    ' O código da função
    ...
    Return ValordeRetorno

End Sub

A seguir temos o código da função getAlunos() que irá receber uma string referente a um comando SQL e que irá retornar um DataTable com as informações dos Clientes:

 Public Function getAlunos(ByVal sql As String) As DataTable
        Try
              Dim cnn As OleDbConnection = New OleDbConnection(strConexao)
              Dim da As OleDbDataAdapter = New OleDbDataAdapter(sql, strConexao)

              Dim dt As DataTable = New DataTable
              da.Fill(dt)
              Return dt

        Catch ex As Exception
              Throw New Exception("Erro ao acessar os dados :
" & ex.Message)
        Finally
            If ConnectionState.Open Then
                  cnn.Close()
              End If

        End Try
    End Function

Observe que o código da função esta contido no interior de um bloco Try/Catch/Finally usado para tratamento de erros.

Capturar e tratar erros(exceções) é uma das tarefas obrigatórias para todo o programador. O VB.NET trouxe uma novidade que nos auxilia no tratamento de erros : o bloco try-catch-finally. (Se você conhece Java esta em casa...).

O bloco try-catch-finally é usado para envolver o código onde existe a possibilidade de uma exceção/erro ocorrer. Um bloco try-catch-finally é constituído das seguintes seções :

  1. O código que pode gerar uma exceção é colocando dentro do bloco try
  2. Se o erro/exceção ocorrer o bloco catch entra em ação e o você faz o tratamento do erro
  3. Dentro do bloco finally você coloca o código que deverá ser executado sempre, quer ocorra ou não a exceção.
Try
 
 'Código que pode gerar(levantar)  um erro.
Catch
   '
Código para tratamento de erros.
Finally
  
'Código de execução obrigatória.
End Try

Obs: O VB.NET ainda mantém , por questões de compatibilidade ,  a sintaxe : "On Error Goto" e você ainda pode usá-la mas prefira usar a estrutura try-catch.

A estrutura try-catch-finally é mais poderosa que a sintaxe anterior pois além de permitir a você fazer um aninhamento de vários tratamentos de erros na mesma estrutura , torna o código mais fácil de ler e manter.

Vamos entender o código usado:

1- cnn = New OleDbConnection(strConexao)

Criamos uma conexão usando a string de conexão - strConexao - que foi definida no início da classe.

O objeto Connection têm a função de gerar uma conexão com uma fonte de dados sendo portanto o objeto fundamental no acesso a dados.

Para estabelecer uma conexão com uma fonte de dados o objeto Connection usa a propriedade ConnectionString que é a string de conexão que deverá ser informada para que a conexão seja efetivamente aberta.

Após realizada a conexão com a fonte de dados podemos usar objetos para receber e enviar dados para a fonte de dados , dentre estes objetos podemos citar : Command e Adapter;

2- Dim da As OleDbDataAdapter = New OleDbDataAdapter(sql, strConexao)

O DataAdapter usado é o OledbDataAdapter e criamos um novo Adapter passando a instrução SQL e a string de conexão:

A função do DataAdapter é a seguinte :

  1. acessar a fonte de dados através de uma conexão prévia
  2. fazer a consulta na base de dados
  3. Obter os dados
  4. Preencher o DataSet

Não pense que o serviço do DataAdapter pare por ai ; quando os dados que foram alterados no DataSet precisam voltar para o banco de dados para atualizar a fonte de dados , novamente o DataAdapter atua :

  1. Ele lê os dados do DataSet
  2. Verifica quais dados foram alterados
  3. Envia ao banco de dados via conexão os dados para atualizar a fonte de dados.

3- Dim dt As DataTable = New DataTable

Definimos um objeto DataTable para ser preenchido e retornado com as informações dos clientes.

Os objetos DataTable são usados para representar e tratar estas tabelas ; além disto podemos criar relacionamentos entres estas tabelas através de objetos DataRelation.

Um objeto DataTable representa uma ou mais tabelas de dados em memória. Os objetos DataTable estão contidos no objeto DataSet e/ou DataView.

4- da.Fill(dt)

Preenchemos o DataTable usando o método Fill.

Para acessar o banco de dados , executar o comando SQL via DataAdapter , trazer os dados e preencher o DataSet usamos o método Fill .

O método Fill retorna a linhas de uma fonte de dados usando a declaração SELECT definida por uma propriedade SelectCommand associada. O objeto Connection associado com a declaração SELECT precisa ser válido mas não precisa ser aberto. Se a conexão for fechada antes de você chamar o método Fill ela será aberta para que os dados possam ser retornados e em seguida fechada novamente. Se a conexão estiver aberta ela permanecerá aberta após o uso do método Fill.

O método Fill então irá incluir as linhas ao objeto DataTable de destino , criando o objeto DataTable , se ele ainda não tiver sido criado. Ao criar o objeto DataTable a operação Fill normalmente cria somente colunas com medadata.

5- Return dt

retornamos um objeto DataTable preenchido.

Se ocorrer alguma exceção durante a execução do código acima será lançada uma exceção:

6- Throw New Exception("Erro ao acessar os dados : " & ex.Message)

A exceção será lançada para a camada de negócios que chamou a função que por sua vez deverá repassá-la a camada de apresentação para ser exibida ao usuário.

7- No interior do bloco Try/Catch/Finally temos o código que verifica se a conexão esta aberto e a fecha. A cláusula Finally garante que o código no seu interior seja executada mesmo ocorrendo uma exceção portanto a conexão sempre será fechada.

If ConnectionState.Open Then
     cnn.Close()
End If

O código completo da classe Camada3_AcessoDados pode ser visto a seguir:

Imports System.Data.OleDb

Public Class Camada3_AcessoDados

    Private cnn As OleDbConnection
    Dim strConexao As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\dados\Cadastro.mdb;"

    Public Function getAlunos(ByVal sql As String) As DataTable
        Try
            cnn = New OleDbConnection(strConexao)
            Dim da As OleDbDataAdapter = New OleDbDataAdapter(sql, strConexao)
            Dim dt As DataTable = New DataTable
            da.Fill(dt)
            Return dt
        Catch ex As Exception
            Throw New Exception("Erro ao acessar os dados : "
& ex.Message)
        Finally
            If ConnectionState.Open Then
                cnn.Close()
            End If
        End Try
    End Function

End Class

Definindo o código da camada de negócios - BLL

É na camada de negócios que se localizam as regras do negócio e da validação dessas regras. (Existem validações feitas na camada de apresentação mas refere-se a validações de dados entrados pelo usuário apenas).

Então, com uma camada de negócios (BLL) podemos efetuar efetuar uma validação de regra de negócio e em seguida passar os objetos para a camada de apresentação.

Como nosso exemplo é muito simples vamos apenas definir a chamada a camada de acesso a dados conforme o código a seguir:

Imports ProjetoTresCamadas_SeparacaoLogica.Camada3_AcessoDados

Public Class Camada2_Negocio

    Public Function getTodosAlunos() As DataTable
        Try
            Dim dal As New Camada3_AcessoDados
            Return dal.getAlunos("Select * from Clientes")
        Catch ex As Exception
            Throw ex
        End Try
    End Function

End Class

Definindo o código da camada de apresentação - UI

Abaixo vemos o código do evento Load do formulário que utiliza a camada de negócios para acessar os dados e exibi-los no controle DataGridView

Imports ProjetoTresCamadas_SeparacaoLogica.Camada2_Negocio
 

Public Class Camada1_frmApresentacao

    Private Sub Camada1_frmApresentacao_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Try
            Dim bll As New Camada2_Negocio
            dgvAlunos.DataSource = bll.getTodosAlunos
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try

    End Sub
 

End Class

Executando o projeto iremos obter:

Dessa forma eu quis mostrar , sem complicar, como é fácil usar a arquitetura em camadas em sua aplicação. Um pouco de disciplina e esforço no início o compensarão com menos esforço e mais tranqüilidade no futuro.

Pegue o projeto completo aqui : ProjetoTresCamadas-SeparacaoLogica.zip

Eu sei é apenas VB .NET, mas eu gosto...

"Eu sou a videira verdadeira e meu Pai é o lavrador. Toda a vara em mim que não dá fruto, a tira; e limpa toda aquela que dá fruto, para que dê mais fruto." (João 15:1-2)

Referências:

José Carlos Macoratti