![]() |
Qual a melhor abordagem para exibir informações de um banco de dados em um formulário Windows Forms ? |
A resposta é curta e grossa: nenhuma das abordagens apresentadas é adequada.
Por que ?
Todas as abordagens ferem o princípio da responsabilidade única e misturam a responsabilidades da camada de apresentação com responsabilidades de acesso a dados.
Vamos analisar o que temos:
Cada um dos artefatos presentes possui uma responsabilidade e deveria realizar uma tarefa específica sem conhecer nada sobre os demais artefatos. Isso é conhecido como baixo acoplamento e alta coesão.
O que temos em todas as abordagens é que a classe Contas é a classe que coordena tudo e tem responsabilidades de acessar e obter os dados e apresentá-los no formulário.
Vamos então apresentar uma abordagem mais consistente seguindo o princípio da responsabilidade única (SRP), do baixo acoplamento e da alta coesão.
Apresentando uma abordagem mais consistente
Primeiro vamos criar uma classe ContaInfo que será responsável apenas por expor os dados que desejamos exibir.
public class ContaInfo
{
public string NumeroConta { get; set; }
public string NomeConta { get; set; }
public string TipoConta { get; set; }
public string NomeBanco { get; set; }
public string NomeCliente { get; set; }
}
|
Como as informações serão obtidas não é problema dessa classe, ela não tem que conhecer nada sobre formulários, nada sobre acesso a dados, SQL, etc. Sua responsabilidade é apenas exibir dados e não obter dados.
Para obter dados vamos criar uma classe de serviço chamada ContasService com um método GetContaPorNumero() que vai usar o número da conta para obter informações e vai retornar essas informações que será usada pela classe ContaInfo.
using System.Data.SqlClient;
namespace WF_ExibirDados
{
public class ContasService
{
private readonly string _connectionString;
public ContasService(string connectionString)
{
_connectionString = connectionString;
}
public ContaInfo GetContaPorNumero(string numeroConta)
{
using (var connection = new SqlConnection(_connectionString))
{
var sql = "SELECT Cliente.Nome, Banco.ContaNome, Banco.BancoNome " +
"Banco.ContaTipo FROM Banco INNER JOIN Cliente ON " +
"Banco.ClienteId = Cliente.ClienteId WHERE " +
"Banco.ContaNumero = @numeroConta";
connection.Open();
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("@numeroConta",numeroConta);
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
return new ContaInfo
{
NumeroConta = numeroConta,
NomeCliente = reader[0].ToString(),
NomeConta = reader[2].ToString(),
NomeBanco = reader[3].ToString(),
TipoConta = reader[4].ToString()
};
}
}
}
}
return null;
}
}
}
|
Agora temos uma classe cuja responsabilidade é acessar o banco de dados. Através do método GetContaPorNumero() ela vai obter e retornar as informações que desejamos exibir usando o número da conta e retornando um tipo ContaInfo. Ela não conhece nada de formulário e não se importa como o objeto retornado será usado.
Neste ponto precisamos tormar um decisão de projeto e conectar os artefatos usados, para isso vamos definir o que cada um precisa saber:
Como fazer para coordenar esses artefatos de forma consistente e sem misturar responsabilidades ?
Usando o padrão MVP - Model View Presenter
O padrão
Model View Presenter (MVP) é um padrão de
design particularmente útil para implementar interfaces de usuário de modo
realizar o desacoplamento dos artefados em responsabilidades distintas
tornando assim o código mais robusto e mais fácil de passar pelos testes
unitários.
Este padrão separa as seguintes responsabilidades:
Abaixo temos uma representação gráfica do padrão MVP :
Analisando nosso exemplo temos a View representanda pelo formulário frmDetalhesConta e o Model representando pela classe ContasService().
Precisamos criar uma classe que vai representar o Presenter e que vai coordenar a iteração entre a View e o Model.
Vamos então criar a classe ContaPresenter com o código abaixo:
using System;
using System.Windows.Forms;
namespace WF_ExibirDados
{
public class ContaPresenter
{
private ContaView _form;
private ContasService _service;
public ContaPresenter(ContaView form, ContasService service)
{
_form = form;
_form.OnShowContaInfo += View_OnShowContaInfo;
_service = service;
}
public void Show()
{
_form.ShowDialog();
}
private void View_OnShowContaInfo(object sender, EventArgs e)
{
var info = _service.GetContaPorNumero(_form.NumeroConta);
if (info == null)
{
MessageBox.Show("Conta não localizada.");
return;
}
_form.NomeConta = info.NomeConta;
_form.TipoConta = info.TipoConta;
_form.NomeBanco = info.NomeBanco;
_form.NomeCliente = info.NomeCliente;
}
}
}
|
Agora nossa classe ContaPresenter atua de forma a coordenar as informações do formulário, a nossa View, e da classe de acesso a dados , o nosso Model.
Para concluir falta definir a classe que chama o método Show da classe Presenter. Vamos criar uma classe chamada ContaView:
using System;
using System.Windows.Forms;
namespace WF_ExibirDados
{
public partial class ContaView : Form
{
public TextBox txtNumeroConta;
private Label label5;
private Button btnConsultar;
public TextBox txtTipoConta;
private Label label4;
public TextBox txtNomeBanco;
private Label label3;
public TextBox txtNomeConta;
private Label label2;
public TextBox txtNomeCliente;
private Label label1;
public event EventHandler OnShowContaInfo;
public string NumeroConta
{
get { return txtNumeroConta.Text; }
set { txtNumeroConta.Text = value; }
}
public string NomeConta
{
get { return txtNomeConta.Text; }
set { txtNomeConta.Text = value; }
}
public string TipoConta
{
get { return txtTipoConta.Text; }
set { txtTipoConta.Text = value; }
}
public string NomeBanco
{
get { return txtNomeBanco.Text; }
set { txtNomeBanco.Text = value; }
}
public string NomeCliente
{
get { return txtNomeCliente.Text; }
set { txtNomeCliente.Text = value; }
}
public ContaView()
{
InitializeComponent();
}
private void GetContaButton_Click(object sender, EventArgs e)
{
if (OnShowContaInfo != null)
{
OnShowContaInfo(this, EventArgs.Empty);
}
}
+ private void InitializeComponent() { }
}
} |
Assim temos a classe ContaView que apenas vai exibir os dados e notificar o Presenter sempre que for necessário ou que algum evento ocorra, e assim ela possa acessar o Model usando uma instância da classe ContaService().
Temos assim que cada artefato atua apenas na sua responsabilidade sem saber nada sobre os demais e ai temos tudo encapsulado e não estamos expondo TextBox de formulários mas sim strings que representam o valor que desejamos exibir.
Essa é uma abordagem mais consistente, desacoplada e que vai facilitar a manutenção e os testes unitários.
Lembrando que usamos o código deste artigo apenas para ilustrar a criação de uma solução usando uma abordagem desacoplada com o padrão MVP em um cenário simplificado.
Pegue
o projeto completo aqui :
WF_ExibirDados2.zip
"Arrependei-vos, pois, e convertei-vos, para que sejam apagados os vossos
pecados, e venham assim os tempos do refrigério pela presença do Senhor,
E envie ele a Jesus Cristo, que já dantes vos foi pregado."
Atos 3:19-20
Veja os
Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique
e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ? |
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Visual Studio - Dica de produtividade - Quick Launch - Macoratti.net
Visual Studio - Dica de produtividade - Nuget - Macoratti.net
C# - Novidades da versão 7.0 - Macoratti
C# - O tipo Dynamic - Macoratti.net
C# - Localizando Arquivos - Macoratti
C# - Usando OpenFileDialog - Macoratti
C# - Exibindo Arquivos e diretórios no TreeView - Macoratti
C# - LINQ : Calculando o total e o tamanho de arquivos em ... - Macoratti
C# - Copiando Arquivos - Macoratti
C# - Compactando e Descompactando diretórios - Macoratti.net