Ir para o conteúdo do rodapé
Iron Academy Logo
Aplicação C#
Aplicação C#

Outras categorias

Interface em C#: Entendendo a Conexão do Formulário de Prêmio (Tim Corey, Lição 09)

Tim Corey
1h 27m 22s

Na série de Tim Corey "C# App Start To Finish", a Lição 09 foca em conectar um formulário de prêmio. Superficialmente, este formulário parece simples—apenas reunir a entrada do usuário, validá-la, criar um modelo e salvá-lo. Mas Tim explica que a verdadeira complexidade está em decidir onde salvar os dados: em um banco de dados, em um arquivo de texto ou ambos. O vídeo de Tim nos conduz pela solução introduzindo um conceito central na programação C#: interfaces.

Neste artigo, vamos examinar mais de perto as interfaces por meio da explicação de Tim para que você possa entender melhor como elas ajudam a criar aplicativos escaláveis e de manutenção fácil.

O Problema: Onde Salvamos os Dados?

Tim começa afirmando o propósito do formulário de prêmio: ele aceita entrada, valida-a e salva-a no armazenamento. Mas ele alerta que a parte complicada é decidir onde armazenar os dados. Ele enfatiza que tutoriais frequentemente pulam isso porque não é fácil, mas ele quer que os aprendizes enfrentem isso de frente.

Ele explica que inicialmente, você pode tentar uma solução simples: verificar se está usando SQL ou um arquivo de texto e executar o processo de salvamento corretamente. Mas Tim rapidamente mostra como isso se torna feio e de difícil manutenção. Se cada formulário tiver que verificar qual tipo de armazenamento usar, o código se torna duplicado, bagunçado e difícil de mudar.

O Modo Feio: Condições Codificadas

Tim esboça um exemplo de pseudocódigo. Ele explica que você pode começar verificando um valor Booleano como usingSQL == true, depois abrir uma conexão de banco de dados, salvar o modelo e retorná-lo com um ID. Então você pode fazer o mesmo para arquivos de texto, gerando manualmente um ID porque arquivos de texto não o fazem automaticamente.

Ele aponta que isso rapidamente se torna repetitivo. Vários formulários precisam dessa lógica, e toda vez que você adiciona uma nova fonte de dados como MySQL, você deve atualizar cada formulário. Tim chama isso de "não escalável" e enfatiza que viola o princípio "DRY" (Don't Repeat Yourself). Ele declara claramente: "Tem que haver uma maneira melhor."

Puxando o Fio: A Abordagem Melhor

Tim apresenta sua estratégia: puxando o fio. Ele começa perguntando que informações o código precisa e de onde elas vêm. Ele identifica duas perguntas-chave:

Como sabemos qual fonte de dados usar?

Como conectamos a duas fontes de dados diferentes para fazer a mesma tarefa?

Tim explica que o ato real de salvar é a única coisa que difere. Do ponto de vista do formulário, ele só precisa dizer: "Aqui está o modelo. Salve-o." O formulário não deve se importar se está salvando em SQL ou em um arquivo de texto.

A Solução: Configuração Global + Interface

Tim sugere um sistema de configuração global. Ele diz que para saber qual fonte de dados usar, o aplicativo precisa de dados globalmente acessíveis, e ele propõe usar uma classe estática para armazenar essas informações. Ele reconhece que variáveis globais geralmente são evitadas, mas neste caso, dados globais são exatamente o que é necessário.

Em seguida, Tim explica o conceito-chave: interfaces. Ele define uma interface como um contrato—uma promessa de que qualquer classe que a implemente conterá certos métodos ou propriedades. Tim enfatiza que isso permite que o aplicativo chame o mesmo método independentemente da fonte de dados. O formulário não se importa se é SQL ou arquivo de texto; ele só se importa em chamar o método.

Tim diz: "Se você precisa fazer a mesma tarefa, mas nos bastidores ela será feita de duas formas diferentes, você precisa de uma interface."

Criando a Interface

Tim passa para a implementação prática criando uma interface na Biblioteca Tracker. Ele a nomeia IDataConnection e explica a convenção de prefixar interfaces com "I". Ele destaca que isso é importante para identificá-la claramente como uma interface.

Tim adiciona um único método à interface:

PrizeModel CreatePrize(PrizeModel model);

Ele explica que este método é um contrato: ele deve existir em qualquer classe que implemente IDataConnection. O formulário chamará este método e espera obter de volta um PrizeModel com um ID. Tim explica que é assim que o formulário permanece agnóstico ao tipo de armazenamento.

Criando a Classe Estática de Configuração Global

Em seguida, Tim cria uma classe estática chamada GlobalConfig. Ele explica que uma classe estática não pode ser instanciada e é globalmente acessível. É aqui que o aplicativo armazenará a lista de conexões de dados disponíveis.

Ele define uma propriedade:

public static List<IDataConnection> Connections { get; private set; }

Tim explica o uso do private set, para que apenas a própria classe possa modificar a lista, enquanto outras partes do aplicativo só podem lê-la.

Ele então cria o método:

public static void InitializeConnections(bool database, bool textFiles)

Este método configura as conexões de dados disponíveis. Tim enfatiza que a lista permite várias conexões, o que significa que o aplicativo pode salvar em SQL, arquivos de texto, ou ambos.

Compreendendo Interfaces: Um Exemplo do Mundo Real

Tim faz uma pausa para tranquilizar os aprendizes de que este é um material complexo, mas alcançável. Ele recomenda assistir ao vídeo uma vez, depois assistir novamente enquanto codifica junto.

Ele explica que a interface é um contrato, e qualquer classe que a implemente deve seguir o contrato. Ele demonstra isso criando uma classe SQLConnector que implementa IDataConnection.

Quando a classe é criada, o Visual Studio avisa que o contrato não está cumprido. Tim mostra como usar "Implement Interface" para gerar automaticamente o método CreatePrize. Ele também explica o scaffold NotImplementedException e por que ele existe—ele permite que o código seja compilado sem fingir que o método funciona.

Criando os Conectores SQL e Texto

Tim adiciona a classe SQLConnector e a classe TextConnector, ambas implementando IDataConnection. Ele explica que, embora salvar em um banco de dados SQL e salvar em um arquivo de texto sejam processos muito diferentes, ambos satisfazem o mesmo contrato de interface.

Ele adiciona um valor de retorno simples de exemplo por enquanto e coloca comentários TODO para se lembrar de implementar a lógica real de salvamento mais tarde. Isso mantém o aplicativo funcional enquanto ainda progride pela lição.

Configuração Final: Conectando a Configuração Global

Tim retorna à classe GlobalConfig e conecta as conexões reais. Ele mostra como inicializar a lista de Connections e adicionar instâncias de SQLConnector e TextConnector a ela.

Ele explica por que são necessárias duas instruções if separadas em vez de if-else—porque o usuário pode querer salvar em ambas as fontes de dados simultaneamente.

Onde Chamar InitializeConnections?

Tim explica que InitializeConnections deve ser chamado no início do aplicativo. Ele modifica Program.cs e chama:

GlobalConfig.InitializeConnections(true, true);

antes de lançar o formulário. Isso garante que a lista de conexões esteja pronta e acessível ao longo do aplicativo.

Em seguida, ele altera o formulário de inicialização para CreatePrizeForm para que possa testar a funcionalidade imediatamente.

Validando o Formulário de Prêmio

Tim abre o formulário e explica a primeira tarefa: validar os quatro campos. Ele prefere manter os manipuladores de eventos limpos, então cria um método privado chamado ValidateForm().

Tim explica que esse método pode ser chamado de qualquer lugar, não apenas do clique do botão. Ele retorna um Booleano indicando se o formulário é válido ou não. Ele mostra seu padrão de uso de uma variável de saída:

bool output = true; return output;

Ele diz que gosta de começar com true porque é mais fácil mudar para false quando algo está errado do que defini-lo como true após cada verificação.

Verificando o Número do Local

Tim explica a primeira validação: o número do local deve ser um inteiro maior que zero.

Ele usa int.TryParse para converter o PlaceNumberValue.Text (uma string) em um inteiro. Tim detalha como o TryParse funciona:

  • Ele recebe uma string e tenta convertê-la em um número.

  • Ele retorna um Booleano indicando sucesso ou falha.

  • Ele usa um parâmetro de saída para output o valor convertido.

Tim enfatiza que o TryParse é mais seguro que o Parse porque não trava com entrada ruim—ele retorna false e define o output como zero.

Ele então explica a lógica:

  • Se placeNumberValidNumber for false, defina output = false.

  • Se placeNumber < 1, defina output = false.

Tim adverte contra o uso de declarações else aqui porque este método possui várias verificações. Se uma verificação falhar, o método ainda deve avaliar as outras para coletar todos os erros.

Validando o Nome do Local

Tim passa para a próxima validação: o nome do local não deve estar vazio.

Ele verifica:

if (placeNameValue.Text.Length == 0) { output = false; }

Tim explica que em uma aplicação real, você exibiria mensagens de erro para cada validação que falhasse. Mas por enquanto, ele mantém simples e apenas retorna true/false.

Validando Montante do Prêmio vs Porcentagem do Prêmio

Tim explica que o formulário deve conter ou um montante de prêmio ou uma porcentagem do prêmio (um deles deve ser maior que zero). Ele observa a diferença importante:

  • Porcentagem do prêmio é um número inteiro (int)

  • Montante do prêmio é um decimal (decimal) porque dinheiro pode incluir centavos.

Ele cria variáveis:

decimal prizeAmount = 0; int prizePercentage = 0;

Então ele usa TryParse para ambos:

bool prizeAmountValid = decimal.TryParse(prizeAmountValue.Text, out prizeAmount); bool prizePercentageValid = int.TryParse(prizePercentageValue.Text, out prizePercentage);

Tim explica que ambos devem ser números válidos. Se qualquer um for inválido, o formulário é inválido.

Em seguida, ele verifica se pelo menos um é maior que zero:

if (prizeAmount <= 0 && prizePercentage <= 0) { output = false; }

Tim também adiciona uma verificação para garantir que a porcentagem esteja entre 0 e 100:

if (prizePercentage < 0 ||prizePercentage > 100) { output = false; }

Ele explica por quê: 150% significaria que você está distribuindo mais do que o montante total de prêmios, o que é impossível.

Usando o Resultado da Validação

Depois que todas as verificações são feitas, Tim explica como usar o resultado:

if (ValidateForm()) { // criar modelo e salvar } else { MessageBox.Show("Este formulário contém informações inválidas. Por favor, verifique e tente novamente."); }

Tim observa que você poderia retornar imediatamente na primeira falha, mas ele opta por executar todas as verificações para que os usuários possam ver todos os erros de validação de uma vez. Isso reduz a frustração porque eles podem corrigir tudo de uma vez só.

Criando o PrizeModel

Tim explica que, uma vez que o formulário é válido, o próximo passo é criar um PrizeModel.

Ele demonstra como instanciar um modelo:

PrizeModel model = new PrizeModel(); model.PlaceName = placeNameValue.Text; model.PlaceNumber = placeNumberValue.Text; // problema: isso é uma string

Tim destaca o problema: PlaceNumber é um int, mas o valor do formulário é uma string. Para resolver isso, ele explica duas opções:

  • Analisar cada valor novamente no formulário (repetitivo).

  • Adicionar uma sobrecarga de construtor no PrizeModel.

Tim escolhe a opção 2.

Construtor Sobrecarga no PrizeModel

Tim adiciona um construtor sobrecarregado que aceita quatro strings:

public PrizeModel(string placeName, string placeNumber, string prizeAmount, string prizePercentage)
{
PlaceName = placeName;
PlaceNumber = int.TryParse(placeNumber, out int placeNumberValue) ? placeNumberValue : 0;
PrizeAmount = decimal.TryParse(prizeAmount, out decimal prizeAmountValue) ? prizeAmountValue : 0;
PrizePercentage = double.TryParse(prizePercentage, out double prizePercentageValue) ? prizePercentageValue : 0;
}

Tim explica que ele não se importa se a análise falhar porque ela será padrão para zero, que é o valor padrão para números de qualquer maneira.

Este construtor permite ao formulário criar um PrizeModel diretamente com entradas de string e deixar o modelo lidar com a análise.

Salvando o Modelo Usando IDataConnection

Agora que o modelo existe, Tim explica como salvá-lo usando a lista global de conexões.

Ele usa um loop foreach:

foreach (IDataConnection db in GlobalConfig.Connections) { db.CreatePrize(model); }

Tim explica que este loop chama CreatePrize() em cada conexão (SQL e arquivo de texto). Embora os métodos ainda não estejam implementados, o formulário funciona e finge salvar os dados. Isso prova que o padrão de interface e configuração global está funcionando.

Testando o Formulário

Tim destaca a importância de testar cedo. Ele adiciona pontos de interrupção e executa o aplicativo.

  • Ele testa primeiro um formulário vazio.

  • Ele passa pelo ValidateForm().

  • Ele vê que a saída é falsa e a validação falha como esperado.

  • Então ele preenche dados válidos e confirma que o construtor preenche o modelo corretamente.

  • Ele também confirma que o loop passa por ambas as conexões.

Tim demonstra que o formulário é funcional e o padrão é validado.

Limpeza Final: Limpando o Formulário

Tim faz alguns ajustes finais:

  • Depois de criar com sucesso um prêmio, limpar os campos do formulário.

  • Definir valores padrão de 0 para valor e percentual de prêmio para que os usuários não precisem digitar zero a cada vez.

Ele então confirma que o formulário é limpo corretamente após uma submissão válida.

O que Vem a Seguir?

Tim encerra o vídeo dizendo que o próximo passo é conectar as classes de conexão SQL e de texto para que realmente salvem os dados.

Ele lembra aos espectadores para ficarem atentos para a próxima lição, onde ele implementará o conector SQL e realmente se conectará ao banco de dados.

Hero Worlddot related to Interface em C#: Entendendo a Conexão do Formulário de Prêmio (Tim Corey, Lição 09)
Hero Affiliate related to Interface em C#: Entendendo a Conexão do Formulário de Prêmio (Tim Corey, Lição 09)

Ganhe mais compartilhando o que você ama.

Você cria conteúdo para desenvolvedores que trabalham com .NET, C#, Java, Python ou Node.js? Transforme sua expertise em renda extra!

Equipe de suporte de ferro

Estamos online 24 horas por dia, 5 dias por semana.
Bater papo
E-mail
Liga para mim