Atenção: esse artigo tem uma palestra complementar. Clique e assista!
Construa uma Aplicação 100% OO - Parte 1
Construa uma Aplicação 100% OO - Parte 2
Construa uma Aplicação 100% OO - Parte 3
Construa uma Aplicação 100% OO - Parte 4
Metodologias de desenvolvimento de sistemas orientados a objetos (MDS-OO)
Técnicas de gestão de projeto
Processo Unificado de Desenvolvimento de Software
UML
Fases e artefatos do projeto de desenvolvimento de sistemas
Para que serve
Uma visão prática e realista do desenvolvimento de sistemas orientados a objetos utilizando técnicas de gestão de projetos e de modelagem de sistemas.
Em que situação o tema é útil
Projetos de desenvolvimento de sistema orientados a objeto.
Resumo do DevMan
Construir um pequeno sistema de computador utilizando as mais modernas técnicas de gerenciamento de projeto, modelagem orientada a objetos e uma metodologia de desenvolvimento de sistemas com abordagem iterativa e incremental.
Este artigo tem o objetivo de demonstrar a execução de um projeto de desenvolvimento de sistema sob a ótica da engenharia de software, fazendo uso do desenvolvimento orientado a objetos. Nesta quinta e última parte, chegamos à implementação do código-fonte, que permitirá compreender como ocorre a transformação do abstrato para o concreto, do modelo para o código implementado.
Nas partes anteriores, modelamos o processo de negócio que será suportado pelo sistema em desenvolvimento, empregando técnicas de levantamento de dados através da observação direta e da entrevista com o cliente. A modelagem do processo de negócio deu origem aos requisitos funcionais e não funcionais do sistema e a construção de uma proposta de solução, materializada no protótipo do sistema.
Passamos então para a especificação de casos de uso, diagramas de atividades e classes, sempre focados na evolução gradativa da solução, passamos pela solução arquitetural e chegamos, finalmente, à implementação do código, que será abordada nessa parte do artigo.
A Implementação
Com o amadurecimento do modelo proposto e tomadas as decisões pertinentes à arquitetura, infraestrutura, ambiente de servidor de aplicação e banco de dados, ferramentas e linguagem de desenvolvimento, estamos aptos a iniciar a fase de implementação.
A implementação é a etapa (disciplina) responsável pela construção dos scripts de criação da estrutura do banco de dados, pela construção do código-fonte do aplicativo e pela execução dos testes, tendo como entrada os artefatos elaborados nas fases anteriores.
Para a codificação, nesse artigo, utilizaremos o Microsoft Visual Web Developer 2008 Express Edition, uma versão freeware do Visual Studio 2008, e a linguagem Visual Basic. Como sistema gerenciador de banco de dados utilizaremos o Firebird Server 2.1.1, um excelente sistema de banco de dados padrão SQL de código aberto (open source).
O servidor de banco de dados Firebird Server pode ser obtido no site oficial do projeto, http://www.firebirdsql.org, e pode ser livremente instalado e utilizado em servidores ou estações de trabalho das principais plataformas do mercado: Win32, Win64, Linux x86, Linux AMD64, MacOSX e Solaris.
Estrutura de pacotes do projeto
Começaremos a implementação pela criação, no Visual Studio, de dois novos projetos: Um projeto web, que chamamos neste exemplo de SCRMweb, para a camada de apresentação e um projeto biblioteca de classes (class library), chamado SCRMsrv, para a camada de negócio e de persistência. Os dois projetos estarão contidos em uma solução denominada SCRM. A Figura 1 apresenta a janela Solution Explorer, com a estrutura dos projetos e os respectivos arquivos de programas implementados.
Figura 1. Estrutura de projetos
Para criar a estrutura de projeto proposta, abra o Visual Studio e, no menu File, selecione a opção New Project. No quadro Project Types, selecione a linguagem de programação a ser utilizada (Visual Basic) e o tipo do primeiro projeto a ser criado (Windows). No quadro Templates, selecione o modelo Class Library. Os demais campos devem ser preenchidos conforme exemplificado na Figura 2. Com esse procedimento criaremos a solução SCRM e o projeto SCRMsrv, sendo necessário ainda que adicionemos à solução um novo projeto ASP.Net Web Application, nomeado como SCRMweb.
Figura 2. Criando a ClassLibrary
Os arquivos de programa (classes) do projeto SCRMsrv foram fisicamente organizados em uma estrutura composta por três pastas (subdiretórios) e logicamente identificados por pacotes (namespaces) análogos às pastas criadas. O projeto foi estruturado da seguinte forma:
· Modelo: Composto de classes que representam as entidades de negócio do sistema, sendo, portanto, constituídas por atributos privados (private) e propriedades públicas (public property), responsáveis pela exposição dos dados da classe (métodos getters e setters).
- Negócio: Composto por classes públicas com métodos, igualmente públicos, responsáveis pelo comportamento e aplicação das regras de negócio. Essas classes não possuem atributos e seus métodos podem receber e/ou retornar as classes (ou coleções de classes) do pacote Modelo.
- Integração: Nesse pacote serão escritas as classes responsáveis pela interação com o sistema de banco de dados, que controlam as conexões, executam as instruções SQL e retornam o resultado para o pacote Negócio, que sempre será o acionador dos métodos do pacote Integração. As classes do pacote Integração serão de visibilidade privativa às classes do projeto (friend).
A estrutura de projeto criada nesses primeiros passos da etapa de implementação está em conformidade com o Diagrama de Pacotes apresentado e discutido na parte 4 deste artigo.
Construindo a camada de negócios e dados
Ao longo da modelagem do sistema – Requisitos, Análise e Projeto – foram confeccionados artefatos (documentos de texto, planilhas e diagramas), previstos na metodologia de desenvolvimento de sistemas adotada, com o objetivo de documentar o sistema e apoiar o trabalho dos projetistas envolvidos.
Comentamos também, mais de uma vez, que durante a etapa de implementação muitos dos artefatos de análise e projeto seriam quase que diretamente convertidos em linhas de código. A criação automática de código a partir de modelos UML é uma realidade de mercado e uma grande vantagem, não apenas para ganhar produtividade e facilitar a vida do codificador, mas, principalmente, para garantir o sincronismo da documentação com o código. Praticamente todas as ferramentas de modelagem, incluindo as gratuitas, possuem, pelo menos, a capacidade de gerar o código a partir do modelo (forward engineering). Algumas ferramentas mais sofisticadas possuem ainda a capacidade de transformação bidirecional de modelo e código, de forma que podemos alterar o modelo e visualizar o código resultante, assim como alterar o código e visualizar as respectivas alterações no modelo.
Em nosso artigo utilizamos o StarUML, uma ferramenta gratuita de modelagem que realiza a transformação unidirecional do modelo em código C#, C++ e Java. Optamos por construir nossa aplicação em VB.Net e, por isso, geraremos nosso código manualmente, iniciando pela construção das classes do pacote de modelo. As classes do pacote Modelo, como explicado anteriormente, representam entidades de negócio. Na Listagem 1 podemos visualizar o código-fonte da classe referente à entidade grupo de recursos.
Listagem 1. Classe GrupoRecursos
Namespace Modelo
Public Class GrupoRecursos
Private numId As Integer
Public Property id() As Integer
Get
Return numId
End Get
Set(ByVal value As Integer)
numId = value
End Set
End Property
Private strDescricao As String
Public Property descricao() As String
Get
Return strDescricao
End Get
Set(ByVal value As String)
strDescricao = value
End Set
End Property
Private strNatureza As Natureza
Public Property natureza() As Natureza
Get
Return strNatureza
End Get
Set(ByVal value As Natureza)
strNatureza = value
End Set
End Property
End Class
End Namespace
Podemos observar, logo na primeira linha da Listagem 1, que foi incluída a declaração Namespace com o nome do pacote correspondente, no caso, Modelo. A seguir, encontramos a declaração da classe como pública (public). Observe também que essa classe é composta apenas por variáveis locais privadas (private) e propriedades públicas. O mesmo procedimento será realizado para as demais entidades identificadas no modelo do projeto.
O próximo passo é a criação das classes do pacote de integração. Essas classes possuem a responsabilidade de estabelecer a ligação (integração) com o gerenciador de banco de dados. A primeira classe do pacote de integração será a classe GrupoRecursosDAO, exibida na Listagem 2.
Listagem 2. Classe GrupoRecursosDAO
Namespace Integracao
''' Classe de manipulação do banco de dados
Friend Class GrupoRecursosDAO
Private Sub New()
End Sub
''' Recupera do banco de dados do sistema um objeto GrupoRecursos
''' Código do grupo de recursos
''' Objeto GrupoRecursos recuperado
Public Shared Function ObterObjeto(ByVal id As Integer) As Modelo.GrupoRecursos
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("SELECT * FROM GrupoRecursos WHERE grpID = @grpID")
Dim objDataReader As Data.IDataReader
Dim objGrupoRecursos As Modelo.GrupoRecursos = Nothing
objComando.Parameters.Add(objDBMediator.Parameter("@grpID", id))
objDataReader = objDBMediator.MontaReader(objComando)
If objDataReader.Read Then
objGrupoRecursos = MontaObjeto(objDataReader)
End If
objDataReader.Close()
objDataReader.Dispose()
objDataReader = Nothing
Return objGrupoRecursos
End Function
''' Recupera do banco de dados do sistema um objeto GrupoRecursos
''' Descrição do grupo de recursos
''' Objeto GrupoRecursos recuperado
Public Shared Function ObterObjeto(ByVal descricao As String) As Modelo.GrupoRecursos
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("SELECT * FROM GrupoRecursos WHERE grpDescricao =
@grpDescricao")
Dim objDataReader As Data.IDataReader
Dim objGrupoRecursos As Modelo.GrupoRecursos = Nothing
objComando.Parameters.Add(objDBMediator.Parameter("@grpDescricao", descricao))
objDataReader = objDBMediator.MontaReader(objComando)
If objDataReader.Read Then
objGrupoRecursos = MontaObjeto(objDataReader)
End If
objDataReader.Close()
objDataReader.Dispose()
objDataReader = Nothing
Return objGrupoRecursos
End Function
''' Recupera um coleção de objetos GrupoRecursos
''' Coleção de objetos GrupoRecursos
Public Shared Function Listar() As List(Of Modelo.GrupoRecursos)
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("SELECT * FROM GrupoRecursos ORDER BY grpDescricao")
Dim objDataReader As Data.IDataReader
Dim listGrupoRecursos As List(Of Modelo.GrupoRecursos) = New List(Of Modelo.GrupoRecursos)
objDataReader = objDBMediator.MontaReader(objComando)
While objDataReader.Read
listGrupoRecursos.Add(MontaObjeto(objDataReader))
End While
objDataReader.Close()
objDataReader.Dispose()
objDataReader = Nothing
Return listGrupoRecursos
End Function
Private Shared Function MontaObjeto(ByRef objDataReader As Data.IDataReader) As Modelo.GrupoRecursos
Dim objGrupoRecursos As Modelo.GrupoRecursos = New Modelo.GrupoRecursos()
objGrupoRecursos.id = objDataReader("grpID")
objGrupoRecursos.descricao = objDataReader("grpDescricao")
objGrupoRecursos.natureza = objDataReader("grpNatureza")
Return objGrupoRecursos
End Function
''' Recupera a quantidade de recursos associados a um determinado grupo de recursos
''' Código de identificação do grupo de recursos a ser excluído do banco de dados
''' Número inteiro referente à quantidade de recursos associados ao grupo de recursos
Public Shared Function ObterQtdRecursosAssociados(ByVal id As Integer) As Integer
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("SELECT COUNT(*) FROM Recurso WHERE grpID = @grpID")
objComando.Parameters.Add(objDBMediator.Parameter("@grpID", id))
Return objDBMediator.MontaScalar(objComando)
End Function
''' Adiciona um novo grupo de recursos ao banco de dados do sistema
''' Objeto GrupoRecursos a ser adicionado ao banco de dados
''' Objeto GrupoRecursos adicionado
Public Shared Function Incluir(ByVal objGrupoRecursos As Modelo.GrupoRecursos) As Modelo.GrupoRecursos
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("SELECT * FROM Add_GrupoRecursos(@grpDescricao,
@grpNatureza)")
objComando.Parameters.Add(objDBMediator.Parameter("@grpDescricao", objGrupoRecursos.descricao))
objComando.Parameters.Add(objDBMediator.Parameter("@grpNatureza", objGrupoRecursos.natureza))
Try
objGrupoRecursos.id = objDBMediator.MontaScalar(objComando)
Return objGrupoRecursos
Catch ex As Exception
Return Nothing
End Try
End Function
''' Altera um grupo de recursos do banco de dados do sistema
''' Objeto GrupoRecursos a ser alterado no banco de dados
''' True se a alteração foi realizada com sucesso e False se ocorreu algum erro
Public Shared Function Alterar(ByVal objGrupoRecursos As Modelo.GrupoRecursos) As Boolean
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("UPDATE GrupoRecursos SET grpDescricao = @grpDescricao,
grpNatureza = @grpNatureza WHERE grpID = @grpID")
objComando.Parameters.Add(objDBMediator.Parameter("@grpDescricao", objGrupoRecursos.descricao))
objComando.Parameters.Add(objDBMediator.Parameter("@grpNatureza", objGrupoRecursos.natureza))
objComando.Parameters.Add(objDBMediator.Parameter("@grpID", objGrupoRecursos.id))
Try
objDBMediator.ExecutaQuery(objComando)
Return True
Catch ex As Exception
Return False
End Try
End Function
''' Exclui um grupo de recursos ao banco de dados do sistema
''' Código de identificação do grupo de recursos a ser excluído do banco de dados
''' True se a exclusão foi realizada com sucesso ou False se ocorreu algum erro
Public Shared Function Excluir(ByVal id As Integer) As Boolean
Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
Dim objComando = objDBMediator.Command("DELETE FROM GrupoRecursos WHERE grpID = @grpID")
objComando.Parameters.Add(objDBMediator.Parameter("@grpID", id))
Try
objDBMediator.ExecutaQuery(objComando)
Return True
Catch ex As Exception
Return False
End Try
End Function
End Class
End Namespace
A classe GrupoRecursosDAO, logo na primeira linha, possui a declaração do Namespace e a identificação do pacote Integração. A quarta linha inicia com a declaração Friend, restringindo a visibilidade da classe as outras classes e objetos do assembly que será gerado.
O uso de tags de documentação é um boa prática. Para tanto, observe que todos os métodos (functions e subs) da classe são precedidos de linhas de comentário com tags de documentação XML. Essas linhas são sempre iniciadas por três aspas simples (apóstrofos), seguidos por tags com a descrição resumida do método (summary), a identificação e a descrição dos parâmetros (param) e, no caso de funções, com o retorno (returns) que devem ser esperados. Esse tipo de documentação é especialmente útil em métodos públicos, que serão utilizados por outros métodos, por serem reconhecidos pelo Visual Studio e exibidos pelo IntelliSense durante a edição do código-fonte.
Para finalizar a organização dos pacotes da biblioteca de classes SCRMsrv, será criado o pacote Negocio para os objetos de negócio (Business Object) da aplicação. Criaremos a classes GrupoRecursosBO, exibida na Listagem 3.
Listagem 3. Classe GrupoRecursosBO
Namespace Negocio
''' Classe para validação de regras de negócio
Public Class GrupoRecursosBO
''' Recupera os dados de um objeto GrupoRecursos
''' Código do grupo de recursos
''' Objeto GrupoRecursos recuperado
Public Shared Function ObterObjeto(ByVal grupoID As Integer) As Modelo.GrupoRecursos
Return Integracao.GrupoRecursosDAO.ObterObjeto(grupoID)
End Function
''' Recupera os dados de um objeto GrupoRecursos
''' Descrição do grupo de recursos
''' Objeto GrupoRecursos recuperado
Public Shared Function ObterObjeto(ByVal descricao As String) As Modelo.GrupoRecursos
Return Integracao.GrupoRecursosDAO.ObterObjeto(descricao)
End Function
''' Recupera um coleção de objetos GrupoRecursos
''' Coleção de objetos GrupoRecursos
Public Shared Function Listar() As List(Of Modelo.GrupoRecursos)
Return Integracao.GrupoRecursosDAO.Listar()
End Function
''' Adiciona um novo grupo de recursos ao banco de dados do sistema
''' Objeto GrupoRecursos a ser adicionado ao banco de dados
''' Objeto GrupoRecursos adicionado
Public Shared Function Incluir(ByRef objGrupoRecursos As Modelo.GrupoRecursos) As List(Of String)
Dim strMsgs As List(Of String) = New List(Of String)
If Not RN06(objGrupoRecursos.descricao) Then
strMsgs.Add(TipoExcecaoBO.GrupoRecursosIncluir_DescricaoRepetida.ToString)
Else
objGrupoRecursos = Integracao.GrupoRecursosDAO.Incluir(objGrupoRecursos)
If objGrupoRecursos Is Nothing Then
strMsgs.Add(TipoExcecaoBO.GrupoRecursosIncluir_Falha.ToString)
End If
End If
Return strMsgs
End Function
''' Altera um grupo de recursos do banco de dados do sistema
''' Objeto GrupoRecursos a ser alterado no banco de dados
''' Resultado da operação de alteração
Public Shared Function Alterar(ByVal objGrupoRecursos As Modelo.GrupoRecursos) As List(Of String)
Dim strMsgs As List(Of String) = New List(Of String)
If Not RN06(objGrupoRecursos) Then
strMsgs.Add(TipoExcecaoBO.GrupoRecursosAlterar_DescricaoRepetida.ToString)
ElseIf Integracao.GrupoRecursosDAO.Alterar(objGrupoRecursos) = False Then
strMsgs.Add(TipoExcecaoBO.GrupoRecursosAlterar_Falha.ToString)
End If
Return strMsgs
End Function
''' Exclui um grupo de recursos ao banco de dados do sistema
''' Código de identificação do grupo de recursos a ser excluído do banco de dados
''' Resultado da operação de exclusão
Public Shared Function Excluir(ByVal grupoID As Integer) As List(Of String)
Dim strMsgs As List(Of String) = New List(Of String)
If Not RN01(grupoID) Then strMsgs.Add(TipoExcecaoBO.GrupoRecursosExcluir_RecursosAssociados.ToString)
If Not RN02(grupoID) Then strMsgs.Add(TipoExcecaoBO.GrupoRecursosExcluir_ReservasFuturas.ToString)
If strMsgs.Count = 0 Then
If Integracao.GrupoRecursosDAO.Excluir(grupoID) = False Then
strMsgs.Add(TipoExcecaoBO.GrupoRecursosExcluir_Falha.ToString)
End If
End If
Return strMsgs
End Function
''' Validar a exclusão de grupo de recursos com recursos associados
Private Shared Function RN01(ByVal grupoID As Integer) As Boolean
If Integracao.GrupoRecursosDAO.ObterQtdRecursosAssociados(grupoID) > 0 Then
Return False
Else
Return True
End If
End Function
''' Validar a exclusão de grupo de recursos com reservas futuras
Private Shared Function RN02(ByVal grupoID As Integer) As Boolean
'TODO: Implementar verificação da existência de solicitações de reservas para datas futuras
Return True
End Function
''' Validar a duplicidade da descrição do grupo de recursos
Private Shared Function RN06(ByVal objGrupoNew As Modelo.GrupoRecursos) As Boolean
Dim objGrupoOld As Modelo.GrupoRecursos = Integracao.GrupoRecursosDAO.
ObterObjeto(objGrupoNew.descricao)
If objGrupoOld Is Nothing Then
Return True
Else
If objGrupoOld.id = objGrupoNew.id Then
Return True
Else
Return False
End If
End If
End Function
''' Validar a duplicidade da descrição do grupo de recursos
Private Shared Function RN06(ByVal descricao As String) As Boolean
Dim objGrupoOld As Modelo.GrupoRecursos = Integracao.GrupoRecursosDAO.ObterObjeto(descricao)
If objGrupoOld Is Nothing Then
Return True
Else
Return False
End If
End Function
End Class
End Namespace
<p align="left">
Além das peculiaridades comentadas anteriormente (declaração Namespace, visibilidade da classe e uso de tags de documentação XML), podemos observar que a classe é composta por métodos públicos, responsáveis pelo comportamento, e por funções privadas, responsáveis pela implementação de regras de negócio. Os métodos privados relativos às regras de negócio, por uma questão de compatibilidade com a documentação do projeto, foram nomeados com a mesma identificação do artefato de especificação de regras de negócio, apresentado na parte 2 deste artigo. Desta forma, a RN01 será implementada no método RN01, facilitando a rastreabilidade do código, o que será muito útil em futuras manutenções evolutivas e corretivas.
A função privada RN02, linhas 80 a 83, implementa a regra de negócio que validará a exclusão de um grupo de recurso com reservas futuras. Essa regra de negócio, apesar de ter sido identificada e especificada durante a fase de análise de requisitos (vide parte 2 desse artigo), somente será detalhada durante a próxima iteração do projeto, não havendo, nesse momento, informações suficientes para realizarmos sua construção. Nesse caso, a função foi criada de maneira que retornará sempre verdadeiro (true), o que possibilita seu uso pelo restante do sistema, mesmo que sem efeito. Quando forem obtidas as informações necessárias, retornaremos a esse arquivo e incrementaremos a função, sem a necessidade de alterar o restante do código. Essa é uma prática comum sempre que trabalhamos com um método de desenvolvimento que seja iterativo e incremental.
Incluímos ainda nessa função uma linha de comentário com a palavra chave “TODO” (do inglês, To Do – A Fazer). Essa linha de comentário fará com que o Visual Studio adicione uma entrada na lista de tarefas “Comments” com o texto da linha de comentário, permitindo a rápida e fácil localização do que está pendente em nosso código-fonte.
Nossa camada de negócios é composta ainda por outros arquivos de programas correspondentes às entidades Recurso e Usuário e aos componentes relacionados, tendo sido implementado, ao todo, 13 arquivos de programa. Por motivos óbvios não abordaremos nesse artigo a construção das demais classes da camada de negócio (Business Objects e Modelos) devido às similaridades existentes.
As classes implementadas são de complexidade baixa, com uma arquitetura modular que nos possibilitou ter métodos bastante coesos e, por consequência, bastante simples. Para a construção do material desse artigo foi alocado um programador experiente que implementou os 13 arquivos de programa dessa camada em apenas um dia de trabalho. Isso foi possível porque visamos uma documentação clara e consistente, além de adotarmos uma arquitetura sólida e padronizada.
Construindo a camada de apresentação
A camada de apresentação, conforme abordado na parte 4 desse artigo, poderá ser implementada em um aplicativo independente da camada de negócios, graças a alta reusabilidade obtida com a arquitetura do sistema, que isolou a camada de negócios em uma aplicação distinta. Poderíamos, por exemplo, criar também uma aplicação para dispositivos móveis, na plataforma Java ME, que reutilizasse a camada de negócios construída. Poderíamos ainda agregar à nossa camada de negócios uma interface WCF (Windows Communication Foundation), para que a camada de negócios pudesse ser hospedada em um computador e a camada de apresentação web pudesse ser hospedada em outro computador, um servidor de aplicação. Estaríamos então operando em um ambiente distribuído e de alta escalabilidade, sem a necessidade de implementar grandes mudanças no código do sistema.
Devemos lembrar também que durante a análise de requisitos foi construído um protótipo da solução proposta (vide parte 2 desse artigo). Na codificação do protótipo, utilizamos uma arquitetura em camadas, no padrão MVC, no intuito de reutilizar as páginas web durante a implementação da camada de apresentação na fase de construção do sistema.
Criamos, no Visual Studio, a solução SCRM, que contém o projeto SCRMweb, nossa camada de apresentação. Para reutilizar o protótipo, devemos copiar para o diretório da aplicação os arquivos das páginas web (aspx e aspx.vb), da folha de estilo (principal.css) e da master page (principal.master). Os arquivos foram copiados de um diretório para o outro porque agora podemos atualizá-los, mantendo o protótipo na situação original, aprovada pelo cliente.
Começaremos pela implementação da rotina de CRUD (Create, Read, Update and Delete) do cadastro de grupos de recursos. No arquivo GrupoRecursosLista.aspx, que apresenta um grid com os grupos de recursos cadastrados, precisaremos reconfigurar o controle ObjectDataSource, alterando as propriedades TypeName e SelectMethod, para que apontem para a classe GrupoRecursosBO, da camada de negócios, e o método Listar, respectivamente. O controle ficará da seguinte forma:
SelectMethod="Listar" TypeName=
"SCRMsrv.Negocio.
GrupoRecursosBO" />
Precisamos ainda incluir o tratamento para alguns dos eventos da página, como por exemplo, o click nos botões da página. Na Listagem 4 vemos o code-behind correspondente.
Listagem 4. Arquivo GrupoRecursosLista.aspx.vb
Imports SCRMsrv
Partial Class GrupoRecursosLista
Inherits System.Web.UI.Page
Protected Sub grdGrupoRecursos_RowDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
Handles grdGrupoRecursos.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim objGrupoRecursos As Modelo.GrupoRecursos = e.Row.DataItem
Dim btnAlterar As ImageButton = e.Row.FindControl("btnAlterar")
Dim btnExcluir As ImageButton = e.Row.FindControl("btnExcluir")
e.Row.Cells(1).Text = Enumeration.getName(GetType(Modelo.Natureza), objGrupoRecursos.natureza.ToString)
btnAlterar.AlternateText = String.Format(Resources.Labels.Grupo_btnAlterar_Alt, objGrupoRecursos.descricao)
btnAlterar.CommandArgument = objGrupoRecursos.id
btnExcluir.AlternateText = String.Format(Resources.Labels.Grupo_btnExcluir_Alt, objGrupoRecursos.descricao)
btnExcluir.CommandArgument = objGrupoRecursos.id
btnExcluir.OnClientClick = String.Format("return confirm('{0}')", _
String.Format(Resources.Labels.Grupo_btnExcluir_Confirm, objGrupoRecursos.descricao))
End If
End Sub
Protected Sub grdGrupoRecursos_RowCommand(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) _
Handles grdGrupoRecursos.RowCommand
If e.CommandName = "Excluir" Then
ExcluiGrupo(e.CommandArgument)
ElseIf e.CommandName = "Alterar" Then
Server.Transfer(String.Format("GrupoRecursosFicha.aspx?action={0}&id={1}", _
+ActionType.Alterar, e.CommandArgument))
End If
End Sub
Protected Sub btnIncluir_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnIncluir.Click
Server.Transfer(String.Format("GrupoRecursosFicha.aspx?action={0}", +ActionType.Incluir))
End Sub
Private Sub ExcluiGrupo(ByVal grupoID As Integer)
Dim objGrupoRecursos As Modelo.GrupoRecursos = Negocio.GrupoRecursosBO.ObterObjeto(grupoID)
Dim strMsgs As List(Of String) = Negocio.GrupoRecursosBO.Excluir(grupoID)
Me.blstMensagem.Items.Clear()
If strMsgs.Count > 0 Then
Me.blstMensagem.CssClass = "validatorErro"
Me.blstMensagem.DataSource = MsgErro.ConverteExcecaoBO(strMsgs)
Me.blstMensagem.DataBind()
Else
strMsgs.Add(String.Format(Resources.Mensagens.SUC004, objGrupoRecursos.descricao))
Me.blstMensagem.CssClass = "validatorSucesso"
Me.blstMensagem.DataSource = strMsgs
Me.blstMensagem.DataBind()
Me.grdGrupoRecursos.DataBind()
End If
End Sub
End Class
Para concluir a rotina de cadastro do grupo de recursos precisamos atualizar a ficha de cadastro. O protótipo o arquivo GrupoRecursosFicha.aspx possui um controle DropDownList com dois itens fixados no próprio controle. A configuração do controle deve ser alterada para que possamos recuperar o conteúdo da coleção Natureza. Incluiremos também o tratamento de eventos da página. A Listagem 5 apresenta o code-behind da página.
Listagem 5. Arquivo GrupoRecursosFicha.aspx.vb
Imports SCRMsrv
Partial Class GrupoRecursosFicha
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Dim numAcao As ActionType = Request.QueryString("action")
If numAcao = ActionType.Alterar Then
Dim numId As Integer = Request.QueryString("id")
Dim objGrupo As SCRMsrv.Modelo.GrupoRecursos =
SCRMsrv.Negocio.GrupoRecursosBO.ObterObjeto(numId)
If objGrupo IsNot Nothing Then
PopulaNatureza()
Me.txtDescricao.Text = objGrupo.descricao
Me.cboNatureza.SelectedValue = objGrupo.natureza
Me.txtDescricao.Focus()
ViewState("action") = ActionType.Alterar
ViewState("id") = numId
End If
ElseIf numAcao = ActionType.Incluir Then
PopulaNatureza()
Me.txtDescricao.Focus()
ViewState("action") = ActionType.Incluir
Else
Server.Transfer("AcessoInvalido.htm")
End If
End If
End Sub
Private Sub PopulaNatureza()
Me.cboNatureza.DataSource = Enumeration.getNames(GetType(SCRMsrv.Modelo.Natureza))
Me.cboNatureza.DataValueField = "value"
Me.cboNatureza.DataTextField = "name"
Me.cboNatureza.DataBind()
End Sub
Protected Sub btnOk_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnOk.Click
Dim strMsgs As List(Of String) = New List(Of String)
Dim strMsgSucesso As String
Dim objGrupoRecursos As Modelo.GrupoRecursos = New Modelo.GrupoRecursos()
objGrupoRecursos.descricao = Me.txtDescricao.Text.Trim
objGrupoRecursos.natureza = Me.cboNatureza.SelectedValue
Me.blstMensagem.Items.Clear()
If ViewState("action") = ActionType.Incluir Then
strMsgSucesso = Resources.Mensagens.SUC001
strMsgs = Negocio.GrupoRecursosBO.Incluir(objGrupoRecursos)
If strMsgs.Count = 0 Then Me.btnOk.Enabled = False
ElseIf ViewState("action") = ActionType.Alterar Then
strMsgSucesso = Resources.Mensagens.SUC002
objGrupoRecursos.id = ViewState("id")
strMsgs = Negocio.GrupoRecursosBO.Alterar(objGrupoRecursos)
Else
Server.Transfer("AcessoInvalido.htm")
Exit Sub
End If
If strMsgs.Count > 0 Then
Me.blstMensagem.CssClass = "validatorErro"
Me.blstMensagem.DataSource = MsgErro.ConverteExcecaoBO(strMsgs)
Me.blstMensagem.DataBind()
Else
strMsgs.Add(strMsgSucesso)
Me.blstMensagem.CssClass = "validatorSucesso"
Me.blstMensagem.DataSource = strMsgs
Me.blstMensagem.DataBind()
End If
End Sub
Protected Sub btnCancelar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCancelar.Click
Server.Transfer("~/GrupoRecursosLista.aspx")
End Sub
End Class
Com muito pouco esforço incrementamos o protótipo e implementamos a camada de apresentação. A rotina de cadastro completa, composta por quatro arquivos de programas, foi implementada por um programador experiente com apenas duas horas de trabalho. Poderíamos ainda ter alocado dois profissionais, um para implementar a biblioteca de classes (SCRMsrv) e outro para implementar a camada de apresentação (SCRMweb), em paralelo, reduzindo a duração total do cronograma do projeto.
Por último, vemos que a reutilização do protótipo garantiu também a integridade entre o que foi prototipado, avaliado e aprovado pelo cliente e o produto final, que por consequência será mais facilmente aprovado.
Os artefatos de projeto, arquivos de código-fonte, scripts de definição de estruturas de banco de dados e todo o material confeccionado durante o desenvolvimento do sistema de controle de recursos materiais, objeto de estudo desse artigo, está disponível para download no site da DevMedia.
Conclusão
Ao longo deste artigo, organizado em cinco partes (mas tínhamos assunto para muito mais), desnudamos o processo de desenvolvimento de um sistema real e factível. Começamos com o termo de abertura do projeto de desenvolvimento e com a declaração de escopo e concluímos, nessa última parte, com a implementação do código-fonte de uma iteração completa. Navegamos pelo mundo da engenharia de software e da modelagem de sistemas, passando do abstrato ao concreto, do artefato ao código implementado e testado.
O artigo foi escrito a quatro mãos, por dois profissionais que têm em comum o entusiasmo pela engenharia de software, mas com conhecimentos específicos distintos, que se somaram. Um especialista em tecnologia .Net e o outro um pesquisador de Java e software livre. A parceria entre dois universos paralelos foi possível porque a engenharia de software e as metodologias de desenvolvimento orientadas a objeto são perenes e independentes dos padrões tecnológicos e dos modismos do mercado. Chegamos até mesmo a discutir, como uma provação adicional, a publicação de duas versões dessa última parte do artigo, uma na plataforma .Net e outra em Java. Acabamos desistindo (por enquanto).
Desejamos fechar essa última parte do artigo com a mesma frase que abriu muitas das partes anteriores – Programar é divertido, mas desenvolver sistemas com qualidade é difícil – tal como um mantra, buscando criar a transformação para o crescimento daqueles que nos lêem.
Nesse artigo foi utilizado o BrOffice.org para a elaboração dos textos, o Microsoft Visual Web Developer 2008 Express Edition como ferramenta de desenvolvimento, o IBExpert Personal Edition da HK Software como ferramenta de gerenciamento do banco de dados e o Firebird Server 2.1.1 como gerenciador de banco de dados. Todas essas ferramentas são gratuitas.
Referências Bibliográficas
Larman, Craig. 2002. Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process. Second Edition. Prentice Hall PTR.
Vários. 2007. Metodologia de Desenvolvimento de Projetos da Dataprev: Paradigma da Orientação a Objetos – Versão 3.1.
Vários. 2007. Implementing Data Transfer Object in .NET with a DataSet.
http://msdn2.microsoft.com/en-us/library/ms998527.aspx
Vários. 2007. Implementing Data Transfer Object in .NET with a Typed DataSet.
http://msdn2.microsoft.com/en-us/library/ms998529.aspx
Vários. 2007. Data Transfer Object.
http://msdn2.microsoft.com/en-us/library/ms978717.aspx
Chiba, Cláudio e Nardi, Alexandre. 2007. Desenvolvimento em Camadas.
http://www.microsoft.com/brasil/msdn/tecnologias/arquitetura/Layers_Developing.mspx
Filho, Fernando Gebara. 2007. Solução para um sistema largamente distribuído.
http://www.microsoft.com/brasil/msdn/tecnologias/Arquitetura/Solucao_Sistema_Distribuido.mspx
Kalidindi, Ravi e Kalidindi, Rohini. 2007. Best Practices to Improve Performance Using Patterns in J2EE. http://www.precisejava.com/javaperf/j2ee/Patterns.htm
Neward, Ted. 2006. Arquitetura Pragmática: Camadas.
http://www.microsoft.com/brasil/msdn/tecnologias/arquitetura/NPALayering.mspx
Panchal, Nimesh. 2003. Implementing MVC Design Pattern in .NET.
http://www.c-sharpcorner.com/uploadfile/napanchal/mvcdesign12052005035152am/mvcdesign.aspx
Macoratti, José Carlos. 2007. Padrões de Projeto: O modelo MVC – Model View Controller.
http://www.macoratti.net/vbn_mvc.htm