C# - Exibindo uma lista de Itens - Uma abordagem OOP - I


Neste artigo vou apresentar a execução de um tarefa simples como a exibição de uma lista de itens de compras em um formulário Windows Forms usando um controle ListBox com uma abordagem orientada a objetos.

É um artigo básico para iniciantes que mostra como aplicar os conceitos da orientação a objetos da linguagem C# em uma aplicação Windows Forms.

Cenário:

Suponha que você tenha uma lista de compras com os itens mostrados a seguir:

Items Tipo Unidade Calorias Preço/Unidade
Banana Fruta Kg 121 1,50
Cenoura Vegetal Kg 27 2,80
Ovo Proteína Dúzia 54 3,50
Alface Vegetal unidade 4 1,99
Leite Matinal Litro 90 2,15
Guarana Bebida Litro 120 2,50
Laranja Fruta Kg 85 1,50
Presunto Proteína Kg 210 5,40
Queijo Matinal Kg 200 6,50
Tomate Fruta Kg 27 3,50
Salmão Peixe Kg 233 8,60
Água Bebida Litro 0 1,25

Você precisa gerenciar a lista de compras acima usando uma aplicação desktop sem usar um banco de dados relacional exibindo os itens em um controle ListBox e seus detalhes em controles TextBox.

Objetivo:

Usar os recursos da programação orientada a objetos da linguagem C# e exibir a lista de compras em um formulário Windows Forms onde a lista de compras deverá ser exibida em um controle ListBox e os detalhes de cada item da lista em controles TextBox do formulário.

Recursos:

Você deverá usar os seguintes recursos :

Antes de iniciar é bom planejar

Esta pode parecer uma tarefa bem simples, afinal temos apenas que exibir os itens em um controle ListBox. O primeiro impulso seria criar um projeto Windows Forms, incluir um controle ListBox e usar sua propriedade Items preencher a coleção de itens com os nomes dos alimentos da lista de compras. Depois basta incluir 5 controles TextBox no formulário para exibir os detalhes dos itens da lista.

Dessa forma o problema esta resolvido !!!!

Não é bem assim....

Essa abordagem vê lista de compras como um conjunto de strings quando na verdade os itens representam objetos do mundo real e precisam ser tratados como objetos e não como uma relação de strings.

Se você seguir esse caminho pode até conseguir exibir os itens e os seus detalhes mas com certeza vai produzir um código sujeito a erros e de difícil manutenção.

Antes de realizar qualquer tarefa, principalmente quando o assunto é o desenvolvimento de software, é bom planejar porque "ninguém planeja fracassar mas fracassa por não planejar".

Vamos então iniciar nossa tarefa conhecendo melhor os componentes que iremos usar para decidir a melhor abordagem para resolver o problema de uma forma robusta.

O controle ListBox é um objeto usando em um formulário Windows Forms usado para exibir uma lista de valores.

A propriedade Items do ListBox representa uma coleção de itens e exibe a informação no ListBox. Os itens listados na coleção são do tipo String.

Normalmente um programador desenvolve código que responde quando um valor exibido no listbox é clicado pela implementação de um método que trata o evento SelectedIndexChanged().

O problema é que os dados armazenados no listbox é muito mais complexo do que apenas um conjunto de strings; como no nosso exemplo o listbox armazena um conjunto de objetos (na verdade um conjunto de referências a objetos).

Armazenar objetos no listbox ao invés de apenas strings é vantajoso pelos seguintes motivos:

Com base nessas informações uma abordagem mais adequada seria:

  1. Popular o listbox com referências a objetos;
  2. Armazenando as referências a objetos implica na criação de classes, uma classe para cada tipo de objeto identificado na lista de items;
  3. Cada item da lista deverá ser implementado sem sua classe. (Classe Banana, Classe Cenoura, etc.);
  4. Objetos diferentes que compartilham atributos e comportamentos comuns podem ser implementados em uma classe derivada que possui uma classe base comum usando o recurso da herança;
  5. Após armazenar as referências aos objetos no listbox, podemos obter apenas a referência a classe base;
  6. Podemos definir o código no formulário Windows Forms para tratar todos os objetos no listbox como se seus tipos de dados fossem do tipo da classe base e invocar os métodos e propriedades públicos do objetos. Assim objetos do tipo Cenoura, Leite ou Banana podem ser tratados como Alimento, classe base de todos os itens da lista de compras.

Com essa abordagem alcançamos as seguintes vantagens:

Dessa forma podemos considerar que essa abordagem nos leva a ter dois componentes independentes ou seja teremos duas camadas:

  1. A camada de apresentação - Encapsulada no Windows Forms onde o código é responsável por responder ás requisições do usuário;
  2. A camada de negócios - Onde iremos implementar nossas classes que irão encapsular os valores dos dados em atributos e expor uma interface pública para manipular os objetos;

Assim os componente das camadas pode ser estendido com novas funcionalidades independentemente um do outro.

A camada de negócios é representada pelas classes que representam os itens da lista.

A seguir temos o diagrama de herança criado para o nosso exemplo onde temos a classe Alimento como classe base e as demais classes como classes derivadas:

A classe Alimento é classe base para os diferentes tipos de alimentos da lista. Ela esta definida com as propriedades : Calorias, Custo, Nome, Preco e Tipo e com os métodos:

A camada de apresentação utiliza uma aplicação Windows Forms onde temos um formulário e os seguintes controles:

Os controles serão dispostos conforme o leiaute da figura abaixo:

Vamos utilizar a propriedade DisplayMember do controle ListBox para exibir os valores associados com um das propriedades publica dos objetos, pois com isso não precisaremos incluir código extra para as classes que serão exibidas no listbox.

A essa propriedade iremos atribuir o nome de uma propriedade pública das classes cujos objetos serão mantidos no listbox.

Criando a solução no Visual Studio 2012

Abra o VS 2012 Express for desktop e clique em New Project;

Selecione Other Project Types -> Visual Studio Solutions e clique em Blank Solution informando o nome ListaCompras;

Estamos criando uma solução vazia chamada ListaCompras;

Nossa solução deverá conter dois projetos:

  1. Um projeto Windows Forms contendo o formulário já descrito acima;
  2. Um projeto Class Library onde iremos definir as classes do nosso domínio;

Nessa abordagem estamos tratando com duas camadas: a camada de interface e a camada de domínio da aplicação.

No menu File clique em Add -> New Project;

Selecione Visual C# e o template Windows Forms Application informando o nome ListaComprasUI;

No menu File clique em Add -> New Project;

Selecione Visual C# e o template Class Library informando o nome ListaComprasModel;

Dessa forma teremos uma solução contendo dois projetos conforme pode ser visto na janela Solution Explorer:

Definindo a camada de domínio

Vamos agora definir a camada de domínio onde iremos criar as classes que representam o domínio da nossa aplicação.

Vamos iniciar criando a classe base Alimento. Nesta classe vamos definir as propriedades:

Um construtor para iniciar essas propriedades e os seguintes métodos:

Renomei o arquivo Class1.cs do projeto ListaComprasModel para Alimento.cs e a seguir defina o código abaixo neste arquivo:

    public class Alimento
    {
       
        public string Nome { get; set; }
        public double Preco { get; set; }
        public double Custo { get; set; }
        public string Tipo { get; set; }
        public string Unidade { get; set; }
        public double Calorias { get; set; }
        
        public Alimento(string _nome, string _tipo, double _calorias, double _preco, string _unidade)
        {
            Nome = _nome;
            Tipo = _tipo;
            Calorias = _calorias;
            Preco = _preco;
            Unidade = _unidade;
        }

        public void SetCusto(double _quantidade)
        {
            Custo += Preco * _quantidade;
        }

        public double  GetCustoCompra(double _quantidade)
        {
            return _quantidade * Preco;
        }

        public void ResetarCusto()
        {
            Custo = 0;
        }
    }

Esta classe será a base para as demais classes sendo assim a classe Pai e as demais classes serão as classes filhas que irão herdar suas propriedades e métodos. Usaremos aqui o conceito de herança da OOP.

Vamos agora definir as demais classes. Para isso vamos incluir no projeto uma nova classe chamada ItensLista.cs. No menu PROJECT clique em Add Class e informe o nome ItensLista.cs;

Vamos definir neste arquivo todas as demais classes ao invés de criarmos um arquivo para cada classe, dessa forma fica mais fácil manter o código.

Se olharmos o diagrama de herança das classes do nosso domínio veremos que as temos as classes Matinal, Bebida, Fruta, Peixe Protiena e Vegetal herdando da classe base e as demais classes herdando dessas classes.

Vamos criar então as classes Matinal, Bebida, Fruta, Peixe Protiena e Vegetal no arquivo ItensLista.cs conforme o código a seguir:

 public class Bebida : Alimento
    {
        private const string TIPO = "Bebida";
        public Bebida(string _nome, double _calorias, double _preco, string _unidade)
            : base(_nome, TIPO, _calorias, _preco, _unidade)
        {
        }
    }

    public class Matinal : Alimento
    {
        private const string TIPO = "Matinal";
        public Matinal(string _nome, double _calorias, double _preco, string _unidade)
            : base(_nome, TIPO, _calorias, _preco, _unidade)
        {
        }
    }

    public class Peixe : Alimento
    {
        private const string TIPO = "Peixe";
        public Peixe(string _nome, double _calorias, double _preco, string _unidade)
            : base(_nome, TIPO, _calorias, _preco, _unidade)
        {
        }
    }

    public class Fruta : Alimento
    {
        private const string TIPO = "Fruta";
        private const string UNIDADE = "Kg";
        public Fruta(string _nome, double _calorias, double _preco)
            : base(_nome, TIPO, _calorias, _preco, UNIDADE)
        {
        }
    }

    public class Proteina : Alimento
    {
        private const string TIPO = "Proteina";
        public Proteina(string _nome, double _calorias, double _preco, string _unidade)
            : base(_nome, TIPO, _calorias, _preco, _unidade)
        {
        }
    }

    public class Vegetal : Alimento
    {
        private const string TIPO = "Vegetal";
        public Vegetal(string _nome, double _calorias, double _preco, string _unidade)
            : base(_nome, TIPO, _calorias, _preco, _unidade)
        {
        }
    }

Observe que cada uma dessas classes herda da classe base Alimento. Isso é indicado pelo sinal de dois pontos logo a após o nome da classe: Ex: public class Bebida : Alimento indica que a classe Bebida herda da classe Alimento.

Note que cada uma das classes definidas esta definindo um construtor usando a sintaxe : nome construtor() : base()

A palavra-chave base é usada para acessar os membros da classe base (propriedades e métodos) a partir de uma classe derivada.

No caso estamos especificando o construtor da classe base a ser chamado durante a criação das instâncias das classes derivadas.

A classe base que é acessada é a classe base especificada na declaração da classe.

Por exemplo, se você especificar class ClassB : ClassA, os membros de ClassA são acessados de ClassB, independentemente da classe base ClassA.

Portanto você não pode usar a palavra-chave base em uma classe estática, isso vai causar um erro.

A seguir vamos definir no mesmo arquivo ItensLista.cs as classes que derivam das classes Vegetal, Proteina, Fruta, Peixe,Matinal e Bebida.

Inclua o código abaixo no arquivo ItensLista.cs:

public class Banana : Fruta
    {
        private const string NOME = "Banana";
        private const double CALORIAS = 121;
        private const double PRECO = 1.50;
        public Banana()
            : base(NOME, CALORIAS, PRECO)
        {
        }
    }

   public class Laranja : Fruta
    {
        private const string NOME = "Laranja";
        private const double CALORIAS = 85;
        private const double PRECO = 1.50;
        public Laranja()
            : base(NOME, CALORIAS, PRECO)
        {
        }
    }

    public class Tomate : Fruta
    {
        private const string NOME = "Tomate";
        private const double CALORIAS = 27;
        private const double PRECO = 3.50;
        public Tomate()
            : base(NOME, CALORIAS, PRECO)
        {
        }
    }

    public class Cenoura : Vegetal
    {
        private const string NOME = "Cenoura";
        private const double CALORIAS = 27;
        private const double PRECO = 2.80;
        private const string UNIDADE = "kg";
        public Cenoura()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

    public class Alface : Vegetal
    {
        private const string NOME = "Alface";
        private const double CALORIAS = 4;
        private const double PRECO = 1.99;
        private const string UNIDADE = "unidade";
        public Alface()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }


    public class Queijo : Matinal
    {
        private const string NOME = "Queijo";
        private const double CALORIAS = 200;
        private const double PRECO = 6.50;
        private const string UNIDADE = "kg";
        public Queijo()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

    public class Leite : Matinal
    {
        private const string NOME = "Leite";
        private const double CALORIAS = 90;
        private const double PRECO = 2.15;
        private const string UNIDADE = "Litro";
        public Leite()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

    public class Guarana : Bebida
    {
        private const string NOME = "Guarana";
        private const double CALORIAS = 120;
        private const double PRECO = 2.50;
        private const string UNIDADE = "Litro";
        public Guarana()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

    public class Agua : Bebida
    {
        private const string NOME = "Agua";
        private const double CALORIAS = 0.1;
        private const double PRECO = 1.25;
        private const string UNIDADE = "Litro";
        public Agua()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

    public class Ovo : Proteina
    {
        private const string NOME = "Ovo";
        private const double CALORIAS = 54;
        private const double PRECO = 3.50;
        private const string UNIDADE = "Duzia";
        public Ovo()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }
 
    public class Presunto : Proteina
    {
        private const string NOME = "`Presunto";
        private const double CALORIAS = 2.10;
        private const double PRECO = 5.40;
        private const string UNIDADE = "kg";
        public Presunto()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

    public class Salmao : Peixe
    {
        private const string NOME = "Salmão";
        private const double CALORIAS = 233;
        private const double PRECO = 8.60;
        private const string UNIDADE = "kg";
        public Salmao()
            : base(NOME, CALORIAS, PRECO, UNIDADE)
        {
        }
    }

Neste código cada classe esta herdando de uma classe que herda da classe Alimento. Assim, para exemplificar temos public class Salmao : Peixe onde a classe Salmao herda da classe Peixe que por sua vez herda da classe Alimento.

Assim a classe Salmao herda os membros da classe Alimento.

Temos ainda que cada classe utiliza o construtor da classe base usando a palavra-chave base. Assim temos:

public Salmao()
: base(NOME, CALORIAS, PRECO, UNIDADE)
{

Onde a classe Salmao esta usando o construtor da classe base Alimento.

Na segunda parte do artigo iremos criar a camada de apresentação.

Veja os Destaques e novidades do SUPER DVD Visual Basic 2013 (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Mat 6:1 Guardai-vos de fazer as vossas boas obras diante dos homens, para serdes vistos por eles; de outra sorte não tereis recompensa junto de vosso Pai, que está nos céus. (Jesus)

Referências:


José Carlos Macoratti