VB .NET -  Usando padrões de projeto na prática - 2


Programar até que é fácil, já desenvolver software de qualidade é uma arte.

Continuando a primeira parte do artigo vamos prosseguir e identificar qual o próximo problema temos que resolver em nossa singela aplicação Windows Forms que inicialmente foi criada sem a preocupação em adotar boas práticas de programação.

Sem olharmos com mais atenção o código da nossa aplicação iremos perceber que ainda temos código cuja responsabilidade é acessar dados espalhado pela nossa aplicação, na camada de interface, incluindo ai comandos SQL e objetos ADO .NET. Isso não é recomendável.

As boas práticas recomendam que a camada de interface não deve conhecer particularidades de acesso a dados, e, que essa responsabilidade deve estar concentrada em uma camada separada e independente. Desta forma a camada de interface, aqui representada pela aplicação Windows Forms, não deveria ter código de acesso a dados e deveríamos criar uma outra camada contendo o código cuja responsabilidade seria realizar as tarefas pertinentes ao acesso a dados.

O padrão DAO - Data Access Object - faz exatamente isso. Seu objetivo é remover a alta dependência do modelo de acesso a dados da nossa aplicação, de forma que se no futuro resolvermos trocar o banco de dados ou adotar outra estratégia de persistência a alteração deverá ser feita apenas em um único lugar. Aliado a isso também temos que podemos ter equipes independentes trabalhando na camada de interface sem ter que conhecer comandos SQL ou ADO .NET.

Usaremos então o padrão Data Access Object - DAO para abstrair e encapsular todo o acesso a fonte de dados sendo que o padrão DAO gerencia a conexão com a fonte de dados para obter os dados armazenados.

Assim, na sua forma mais básica, o padrão DAO é responsável por operar o mecanismo de persistência em nome da aplicação executando as quatro operações básicas – Criar, Recuperar , Alterar, Apagar – conhecidas pela sigla CRUD : Create, Retrive, Update , Delete.

Então o nosso próximo passo será implementar o padrão de projeto DAO em nosso projeto removendo assim as instruções SQL e os objetos ADO .NET  e suas referências para acesso a dados da camada de interface ou seja da aplicação Windows Forms.

Podemos criar uma nova classe em nosso projeto Persistencia que foi criado no artigo anterior para implementar o padrão DAO, mas, uma opção melhor é  especificar o padrão DAO através de uma interface ao invés de uma classe concreta. Com isso facilitamos o trabalho de implementar novos processos de persistência e impedimos que sejam criadas referências a classes concretas diminuindo o acoplamento.

Uma interface é parecida com uma classe abstrata; a diferença é que uma classe abstrata pode possuir métodos que não estejam implementados e pode possuir métodos que estejam implementados.

Uma interface somente possui métodos que não possuem implementação.

Uma interface possui somente métodos que não estão implementados e que devem ser implementados pela classe que usar a interface.

Como o VB.NET não suporta herança múltipla as interfaces permitem que uma classe estenda múltiplas interfaces contornando o problema (se é que isto é um problema ). Para implementar uma interface o VB.NET usamos o modificador - Implements .

As interfaces são declaradas usando a palavra-chave - Interface. Geralmente o nome dado a uma interface começa com a letra I.

Para isso vamos criar a interface IClienteDAO no projeto Persistencia. Clique com o botão direito do mouse sobre o projeto Persistencia e selecione a opção Add -> New item;

A seguir selecione o template Interface e informe o nome IClienteDAO.vb e clique em Add;

Vamos definir na interface o código conforme abaixo:

Public Interface IClienteDAO(Of T)
    'Sub Insert(ByVal Obj As T) 
    'Function Update(ByVal Obj As T) As Boolean
    'Function Delete(ByVal Obj As T) As Boolean
    'Function Find(ByVal id As ID) As T
    Function ExibirTodos() As List(Of T)
    Sub Gravar(ByVal obj As T)
    Function Consultar(ByVal nome As String) As DataTable 

End Interface

Como nosso projeto Windows Forms é muito simples e até o momento possui somente as funcionalidades para Consultar e Incluir um cliente eu defini os métodos Gravar() que inclui um cliente e Consultar que consulta um cliente. O método ExibirTodos() que exibe todos os clientes nos vamos implementar na interface depois.

Obs: Os demais métodos que estão comentados foram colocados como exemplos pois são os mais comumente usados.

Observe que estamos trabalhando com Generics e que nossa interface é fortemente tipada (Of T).Estamos trabalhando com List(Of T) que representa uma lista fortemente tipada de objetos que podem ser acessados através de um índice. (Fornece os métodos Search, Sort e efetua a manipulação da lista. )

Dessa forma o método ExibirTodos retorna uma lista de um tipo e o método Gravar recebe um tipo. A que tipo estamos nos referindo ?

Para nossa aplicação trata-se do objeto do nosso domínio, ou seja, o Cliente.  Dessa forma teremos que criar uma classe Cliente para representar o nosso objeto de domínio e que será o tipo usado na implementação da interface.

Clique com o botão direito sobre o projeto Persistencia e selecione o template class e informe o nome Cliente.vb e clique em Add;

A seguir vamos definir na classe Cliente 3 propriedades : Codigo, NomeCliente e idadeCliente;

Lembre-se que nossa tabela Clientes possui 3 campos : Id, nome e idade.

Public Class Cliente

    Private _id As Integer
    Private _nome As String
    Private _idade As Integer

    Public Property Codigo As Integer
        Get
            Return _id
        End Get
        Set(ByVal value As Integer)
            _id = value
        End Set
    End Property
    Public Property NomeCliente As String
        Get
            Return _nome
        End Get
        Set(ByVal value As String)
            _nome = value
        End Set
    End Property

    Public Property IdadeCliente() As Integer
        Get
            Return Me._idade
        End Get
        Set(ByVal value As Integer)
            If value > 100 Or value < 18 Then
                Throw New Exception("Idade Inválida")
            Else
                Me._idade = value
            End If
        End Set
    End Property
End Class
A classe Cliente apresenta somente 3 propriedades :
  • Codigo
  • NomeCliente
  • IdadeCliente

Sendo que na propriedade IdadeCliente temos uma restrição quando ao
valor que a mesma pode receber.

A propriedade somente aceita valores entre 18 e 100.

A tentativa de atribuir um valor fora dessa faixa irá causar um exceção.

 

Agora que já temos definidos a interface IClienteDAO e a classe Cliente vamos implementar a interface definindo uma classe chamada ClienteDAO.

Abaixo temos o esquema de implementação do padrão DAO no nosso projeto:

Clique com o botão direito do mouse sobre o projeto Persistencia e selecione a opção Add -> New item;

A seguir selecione o template Interface e informe o nome ClienteDAO.vb e clique em Add;

O código da classe ClienteDAO.vb que é uma classe concreta que implementa a interface IClienteDAO é o seguinte:

1- Devemos usar os seguintes namespaces :

Imports System.Data
Imports
System.Data.SqlClient

2- A definição da assinatura da classe deve conter a palavra Implements e o nome da interface a definição do tipo usado na implementação:

Public Class ClienteDAO
       
Implements IClienteDAO(Of Cliente
)

3- Ao teclar ENTER no final da definição da interface os métodos que devem ser implementados serão criados com suas assinaturas conforme abaixo:

Imports System.Data
Imports
System.Data.SqlClient

Public Class ClienteDAO
     
Implements IClienteDAO(Of Cliente
)

    Public Function Consultar(ByVal nome As String) As System.Data.DataTable Implements IClienteDAO(Of Cliente).Consultar

    End Function

   Public Function ExibirTodos() As System.Collections.Generic.List(Of Cliente) Implements IClienteDAO(Of Cliente).ExibirTodos

    End Function

    Public Sub Gravar(ByVal cliente As Cliente) Implements IClienteDAO(Of Cliente).Gravar

    End Sub
End
Class

O código completo da classe concreta ClienteDAO é dado a seguir:

Imports System.Data
Imports System.Data.SqlClient

Public Class ClienteDAO
    Implements IClienteDAO(Of Cliente)

    Private Shared ReadOnly instancia As New ClienteDAO()

    Sub New()
    End Sub

    Public Shared Function GetInstance() As ClienteDAO
        Return instancia
    End Function
 
    Public Function Consultar(ByVal nome As String) As DataTable Implements IClienteDAO(Of Cliente).Consultar
        Try
            Using con As SqlConnection = ConexaoBD.GetInstancia.GetConnection()
                Try
                    con.Open()
                    Dim sql As String = ("Select nome, idade from clientes where nome = '" & nome & "'")
                    Dim cmd As SqlCommand = New SqlCommand(sql, con)
                    Dim da As SqlDataAdapter = New SqlDataAdapter(cmd)
                    Dim cliente As DataTable = New DataTable
                    da.Fill(cliente)
                    Return cliente
                Catch ex As SqlException
                    Throw ex
                Finally
                    con.Close()
                End Try
            End Using
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Sub Gravar(ByVal cliente As Cliente) Implements IClienteDAO(Of Cliente).Gravar
        Try
            Using con As SqlConnection = ConexaoBD.GetInstancia.GetConnection()
                Try
                    con.Open()

                    Dim cmd As SqlCommand = New SqlCommand()
                    cmd.Connection = con
                    cmd.CommandText = "INSERT INTO  Clientes (nome, idade) values (@nome, @idade)"

                    Dim parNome As SqlParameter = New SqlParameter("@nome", cliente.NomeCliente)
                    Dim parIdade As SqlParameter = New SqlParameter("@idade", cliente.IdadeCliente)
                    cmd.Parameters.Add(parNome)
                    cmd.Parameters.Add(parIdade)

                    cmd.ExecuteNonQuery()
                Catch ex As SqlException
                    Throw ex
                Finally
                    con.Close()
                End Try
            End Using
        Catch ex As Exception
            Throw ex
        End Try
    End Sub
    Public Function ExibirTodos() As System.Collections.Generic.List(Of Cliente) Implements IClienteDAO(Of Cliente).ExibirTodos
        Try
            Using con As SqlConnection = ConexaoBD.GetInstancia.GetConnection()
                Try
                    con.Open()
                    Dim sql As String = ("Select Id,nome, idade from clientes")
                    Dim listaClientes As IList(Of Cliente) = New List(Of Cliente)
                    Dim cmd As SqlCommand = New SqlCommand(sql, con)
                    Dim dr As SqlDataReader = cmd.ExecuteReader
                    While (dr.Read)
                        Dim cliente As New Cliente
                        cliente.Codigo = CLng(dr("Id"))
                        cliente.NomeCliente = dr("nome")
                        cliente.idadeCliente = CInt(dr("idade"))
                        listaClientes.Add(cliente)
                    End While
                    Return listaClientes

                Catch ex As SqlException
                    Throw ex
                Finally
                    con.Close()
                End Try
            End Using
        Catch ex As Exception
            Throw ex
        End Try
    End Function
End Class

 

Além dos métodos Gravar, Consultar e ExibirTodos que foram definidos na interface e implementados temos o método GetInstance que retorna uma instância da classe ClienteDAO. Boa parte do código de implementação dos métodos foram retirados da camada de interface.

A instância é criada na declaração: Private Shared ReadOnly instancia As New ClienteDAO()

Como criamos a classe ClienteDAO implementando a interface IClienteDAO já temos o nosso padrão DAO que será o responsável pelo acesso e a persistência dos dados. Vamos agora usar o padrão cliente em nosso projeto Windows Forms.

A primeira providência será remover do projeto Windows Forms , os formulários do projeto qualquer referência aos objetos ADO .NET , instruções SQL , etc.

Em seguida vamos usar o padrão DAO criado no projeto Persistencia e para que o projeto Windows tenha acesso as classes criadas temos que incluir uma referência ao projeto Persistencia no projeto CadastroClientes;

Clique com o botão direito do mouse sobre o projeto CadastroClientes e selecione a opção Add Reference;

Em seguida na janela Add Reference selecione a aba Projects, selecione o projeto Persistencia e clique em OK;

Com isso podemos alterar o código do formulário frmConsultar.vb conforme vemos abaixo:

 Imports Persistencia
 Public Class frmConsultar

    Private Sub btnConsultar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConsultar.Click
        Try
            Dim cliente As DataTable = Persistencia.ClienteDAO.GetInstance.Consultar(txtNomeCliente.Text)
            gdvCliente.DataSource = cliente
        Catch ex As Exception
            MessageBox.Show("Erro : " & ex.Message)
        End Try
    End Sub
End Class

 

Note que temos uma referência ao projeto Persistencia: Imports Persistencia

No código estamos obtendo uma referência da classe ClienteDAO e usando o método Consultar passando como parâmetro o nome informado no controle txtNomeCliente.textPersistencia.ClienteDAO.GetInstance.Consultar(txtNomeCliente.Text)

Vamos alterar também o código do formulário frmIncluir.vb conforme a seguir:

Imports Persistencia
Public Class frmIncluir
    Private Sub btnGravar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGravar.Click
        Try
            Dim cliente As New Cliente
            cliente.NomeCliente = txtNome.Text
            cliente.idadeCliente = CInt(txtIdade.Text)
            Persistencia.ClienteDAO.GetInstance().Gravar(cliente)
        Catch ex As Exception
            MessageBox.Show("Erro" & ex.Message)
        End Try
    End Sub

End Class

Note que temos uma referência ao projeto Persistencia: Imports Persistencia

A seguir criamos uma instância da classe Cliente e atribuímos os valores informados nos controles TextBox ao objeto e depois obtemos uma instância da classe ClienteDAO e usamos o método Gravar passando o objeto atualizado.

Agora vamos incluir um novo formulário no projeto para exibir todos os clientes cadastrados através do método ExibirTodos que implementamos na classe ClienteDAO;

No menu Project selecione Add Windows Forms  e informe o nome frmClientes.vb;

A seguir inclua um controle DataGridView (name=gdvClientes) no formulário e em através do DataGridVeiw Tasks clique no link : Dock in Parent Container;

Abaixo temos o leiaute do formulário frmClientes que exibirá todos os clientes no controle DataGridView:

O código do formulário é exibido abaixo:

Imports Persistencia
Public Class frmClientes

    Private Sub frmClientes_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Try
            Dim clientes As List(Of cliente) = Persistencia.ClienteDAO.GetInstance.ExibirTodos
            gdvClientes.DataSource = clientes
        Catch ex As Exception
            MessageBox.Show("Erro: " & ex.Message)
        End Try
    End Sub
End Class

Aqui temos novamente a referência ao projeto Persistencia: Imports Persistencia

Obtemos uma referência da classe ClienteDAO e usamos o método ExibirTodos;

Lembrando que o método retorna uma lista tipada de objetos Clientes que é exibida no DataGridView;

Para completar vamos incluir no formulário formulário frmMenu um link para abrir o formulário frmClientes;

Inclusão do LinkLabel Exibir Clientes e no evento Click do LinkLabel temos o código:
 
Private Sub LinkLabel3_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel3.LinkClicked

      My.Forms.frmClientes.Show()

End Sub

Já podemos executar o projeto e verificar se nossa implementação esta funcionando.

Abaixo temos o resultado da execução da opção Exibir Clientes:

Concluímos assim a implementação do padrão DAO - Data Access Object em nossa aplicação.

Aguarde mais artigos sobre a utilização de padrões de projetos.

Eu sei á penas Visual Basic e melhores práticas, mas eu gosto...

Simples, simples assim...

Referências:


José Carlos Macoratti