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


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

Neste artigo eu procuro mostrar como usar os padrões de projeto na prática em uma aplicação Windows Forms. Vale lembrar que padrões de projeto não pertencem a uma tecnologia ou a uma empresa; os padrões de projeto são soluções para problemas que alguém um dia teve e resolveu aplicando um modelo que foi documentado e que você pode adaptar integralmente ou de acordo com necessidade de sua solução.

Além dos padrões de projetos documentados e conhecidos (Padrões Gof) existem os padrões comuns que são inerentes ao conhecimento humano e que são usados intuitivamente para resolver problemas do dia a dia.

Os padrões de projetos não são difíceis de entender mas usá-los com sabedoria e bom senso na prática é uma questão de experiência.

Neste artigo eu procuro abordar de forma natural como reconhecer e saber como aplicar o padrão de projeto adequado a situação problema.

Para começar vamos criar uma aplicação Windows Forms com acesso a dados, que usa ADO .NET via código, onde teremos um banco de dados SQL Server chamado Cadastro.mdf e uma tabela Clientes.

A aplicação Windows Forms deverá realizar as operações de incluir e consultar dados da tabela Clientes.

A estrutura da tabela Clientes é a seguinte : Id, Nome, Idade onde Id é chave primária e do tipo Identity.

Irei criar a aplicação usando o VS 2010 Professsional (trial edition) onde irei criar uma aplicação Windows Forms padrão que usa o código embutido nos eventos dos controles do formulário para depois ir mostrando como podemos usar padrões de projeto para tornar a aplicação mais robusta, escalável e fácil de manter e testar.

Criando um Cadastro de Clientes sem usar padrões de projeto

Abra o VS 2010 e no menu File selecione New Project;

A seguir selecione Other Project Types -> Visual Studio Solutions -> Blank Solution;

Informe o nome UsandoPadroesProjetos e clique no botão OK;

A seguir , na janela Solution Explorer, clique com o botão direito do mouse sobre a solução criada e escolha : Add -> New Project;

Escolha a linguagem Visual Basic e selecione o template Windows Forms Application; Informe o nome CadastroClientes e clique em OK;

Vamos alterar o nome do formulário form1.vb criado por padrão para frmIncluir.vb e vamos incluir mais três formulários no projeto;

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

Repita a operação e inclua o formulário frmMenu.vb;

A seguir vamos definir em cada um dos formulários: frmMenu, frmConsultar e frmIncluir, o seguinte leiaute :

- Dois controles LinkLabel:

- Consultar Clientes: No evento LInkClicked:

    My.Forms.frmConsultar.Show()

- Incluir Clientes : Código do evento LinkClicked:

    My.Forms.frmIncluir.Show()

- Um controle Label - Nome do Cliente

- Um controle TextBox - txtNomeCliente

- Um Button - btnConsultar

- Um DataGridView - gdvCliente

Dois controles Label - Nome do Cliente e Idade do Cliente

- Um controle TextBox - txtNome
- Um controle TextBox - txtIdade

- Um Button - btnGravar

 

Vamos agora definir o código que estarão nos eventos dos controles:

1- Formulário Consultar Clientes:

No evento Click do botão Consultar inclua o código a seguir:


    
    

Private Sub btnConsultar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConsultar.Click

        Dim strsql = "Data Source=MAC-PC\SQLEXPRESS;Initial Catalog=Cadastro;Integrated Security=True"
        Using con As New SqlConnection(strsql)
            con.Open()
            Dim sql As String = ("Select nome, idade from clientes where nome = '" & txtNomeCliente.Text & "'")
            Dim cmd As SqlCommand = New SqlCommand(sql, con)
            Dim da As SqlDataAdapter = New SqlDataAdapter(cmd)
            Dim cliente As DataTable = New DataTable
            da.Fill(cliente)
            gdvCliente.DataSource = cliente
            con.Close()
        End Using

End Sub

2- Formulário Incluir Clientes:

No evento Click do botão Gravar inclua o código a seguir:

  Private Sub btnGravar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGravar.Click
    
    Dim strsql = "Data Source=MAC-PC\SQLEXPRESS;Initial Catalog=Cadastro;Integrated Security=True"

        Using con As New SqlConnection(strsql)
            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", txtNome.Text)
            Dim parIdade As SqlParameter = New SqlParameter("@idade", CInt(txtIdade.Text))
            cmd.Parameters.Add(parNome)
            cmd.Parameters.Add(parIdade)
            cmd.ExecuteNonQuery()
            con.Close()
        End Using
    End Sub

Concluímos dessa forma nossa aplicação Windows Forms onde a partir do formulário frmMenu podemos chamar o formulário de consulta e do inclusão.Uma aplicação muito simples na verdade, mas que já serve para nosso propósito.

Antes de continuar eu quero alertar que ninguém aplica padrões de projeto nessa sistemática que estamos usando, ou seja, primeiro desenvolve uma solução e depois procura identificar qual padrão pode ser aplicado a ela. Usar padrões de projeto é como andar de bicicleta ou dirigir um carro, depois que você incorporou o conceito e teve um tempo de experiência você passa usá-los naturalmente.

Aplicando padrões de projeto

Mesmo sendo muito simples e tendo pouco código podemos identificar na nossa aplicação que o código para consultar e para incluir usam a mesma string de conexão, ou seja, ela esta esparramada pela aplicação e, se houver uma alteração nessa string de conexão, teremos que alterar o código dos dois formulários. Imagine se a aplicação tivesse uns 20 formulários usando essa mesma string de conexão ????

Quem nos poderá ajudar a resolver este problema ??

Aqui o primeiro padrão entra em cena, o padrão Singleton que é classificado como um padrão Criacional pois trata da criação de objetos.  

Diagrama de classes simplificado para o padrão Singleton

Eu já tratei desse padrão no artigo: O padrão Singleton portanto não vou entrar em detalhes.

Em resumo: O padrão Singleton faz com que uma classe só possa ter uma instância com um ponto global de acesso  a ela.

Como vamos implementar o padrão Singleton em nosso projeto ?

Poderíamos fazer isso de diversas formas mas em nosso exemplo eu vou criar um novo projeto chamado Persistencia e incluí-lo na nossa solução e nesse projeto irei criar uma classe que implementa o padrão SIngleton.

No menu File clique em Add e a seguir em New Project;

A seguir selecione o template Class Library,  informe o nome Persistencia e clique em Ok;

Terminada esta etapa teremos uma solução chamada UsandoPadroesProjetos com dois projetos: CadastroClientes e Persistencia;

A seguir altere o nome da classe Class1.vb para ConexaoBD.vb e inclua o seguinte código na classe:

Imports System.Data
Imports System.Data.SqlClient

Public Class ConexaoBD

#Region "Métodos"
    ''' <summary>
    '''  O objeto intancia representa uma instância única da classe ConexaoBD;
    '''   *private = indica que o objeto só poderá ser acessado dentro da classe de origem,
    '''   *shared = define o atributo instancia como um objeto da classe, e, não da instância da classe
    '''   *readonly = implica que seu valor só poderá ser alterado na sua declaração ou dentro de um método construtor.
    ''' </summary>
    Private Shared ReadOnly instancia As New ConexaoBD()
    ''' <summary>
    '''  Restringimos o construtor padrão com o modificador private, o que implica
    '''  que apenas a própria classe pode se instanciar, ou seja, não pode ser 
    '''  instanciada diretamente.
    ''' </summary>
    Private Sub New()
    End Sub

    ''' <summary>
    '''  Método estático que retorna a única instância da classe.
    '''  Só por este método as outras classes do sistema poderão utilizar
    '''  a instância de ConexaoBD.
    ''' </summary>
    ''' <returns>Instância única da classe</returns>
    Public Shared Function GetInstancia() As ConexaoBD
        Return instancia
    End Function

    ''' <summary>
    ''' Retorna uma conexão com o banco de dados.
    ''' </summary>
    ''' <returns>objeto de conexão com o banco de dados.</returns>
    Public Function GetConnection() As SqlConnection
        ' Obtem a string de conexão
        Dim strConexao As String = "Data Source=MAC-PC\SQLEXPRESS;Initial Catalog=Cadastro;Integrated Security=True" 
        ' Retorna uma conexão.
        Return New SqlConnection(strConexao)
    End Function
#End Region
End Class

Com esta classe resolvemos o problema da string de conexão esparramada pelo código agora somente esta classe conhece a string de conexão e retorna uma instância da conexão com o banco de dados. Qualquer mudança nesse quesito bastará alterar esta classe.

Agora temos que remover a string de conexão do código dos formulários e alterar a forma como a conexão com o banco de dados é obtida.

Antes temos que fazer uma referência no projeto CadastroClientes a projeto Persistencia, para isso clique com o botão direito do mouse sobre  o projeto CadastroClientes e selecione a opção Add Reference;

Em seguida abra a guia Projects e selecione o projeto Persistencia e clique em OK;

Agora no vamos alterar os formulários frmIncluir.vb e frmConsultar.vb conforme abaixo:

1- Novo código do formulário frmConsultar.vb:

Imports System.Data
Imports System.Data.SqlClient
Imports Persistencia

Public Class frmConsultar

    Private Sub btnConsultar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConsultar.Click
 
        Try
            Using con As SqlConnection = ConexaoBD.GetInstancia.GetConnection()
                Try
                    con.Open()
                    Dim sql As String = ("Select nome, idade from clientes where nome = '" & txtNomeCliente.Text & "'")
                    Dim cmd As SqlCommand = New SqlCommand(sql, con)
                    Dim da As SqlDataAdapter = New SqlDataAdapter(cmd)
                    Dim cliente As DataTable = New DataTable
                    da.Fill(cliente)
                    gdvCliente.DataSource = cliente
                Catch ex As SqlException
                    Throw ex
                Finally
                    con.Close()
                End Try
            End Using
        Catch ex As Exception
            Throw ex
        End Try
 
    End Sub
End Class

2- Novo código do formulário frmIncluir.vb:

Imports System.Data
Imports System.Data.SqlClient
Imports Persistencia
Public Class frmIncluir

    Private Sub btnGravar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGravar.Click

        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", txtNome.Text)
                    Dim parIdade As SqlParameter = New SqlParameter("@idade", CInt(txtIdade.Text))
                    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
 
End Class

Desta forma acabamos de aplicar o primeiro padrão de projeto a nossa aplicação. Na próxima parte estaremos aplicando mais padrões de projeto de forma a tornar a aplicação mais robusta.

Aguarde continuação em :  VB .NET -  Usando padrões de projeto na prática - 2

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

Simples, simples assim...

Referências:


José Carlos Macoratti