.NET

15 ago, 2014

Programação Orientada a Objetos em 10 lições práticas – Parte 04

Publicidade

Na terceira parte do artigo, apresentei a criação de sua primeira aplicação orientada a objetos, onde aprendemos a criar classes, propriedades e métodos em uma aplicação Windows Forms. Vamos estender um pouco mais os nossos conhecimentos aprendendo a usar herança para criar classes especializadas.

Lição 10 – Juntando todas as partes

Embora VB .NET seja realmente uma linguagem orientada a objetos, você pode usar a linguagem da mesma forma que usa uma linguagem estruturada como Visual Basic ou Pascal. Se você não incorporar os conceitos da orientação a objetos e aplicá-los em seus projetos, construirá aplicações usando os mesmos conceitos das linguagens estruturadas. Isso não é de todo ruim, mas você acaba não usando os recursos da linguagem e continua a construir projetos usando o paradigma procedural.

É como se você tivesse uma Ferrari, mas se comportasse como se tivesse um Fusca. O segredo para incorporar os conceitos da orientação a objetos em suas aplicações e conhecer bem os conceitos e praticar.

Então, vamos lá…

Os exemplos mostrados aqui foram construídos com base nos exemplos do livro OOP with Microsoft Visual Basic .NET and Microsoft Visual C# Step by Step.

Usando herança para criar classes especializadas

Nesta aplicação você vai aprender a:

  • Aprender a usar o conceito de herança
  • Utilizar a palavra-chave Me
  • Usar a palavra-chave MyBase
  • Criar campos em classes usando o modificador Protected
  • Criar métodos usando o modificador Overridable
  • Criar métodos usando o modificador Overrides

Objetivo: Criar uma pequena aplicação para controlar os saques, depósitos e saldos de uma conta pessoal usando os conceitos programação orientada a objetos na linguagem VB .NET.

Recursos usados: Visual Studio 2012 Express for Windows desktop.

Nota: Neste momento já se encontra disponível a versão 2013.

É importante salientar que a ferramenta usada é gratuita e não possui restrições, sendo totalmente funcional. Ao fazer o download da ferramenta, você também pode baixar o pacote de idiomas para localizar o produto para a língua portuguesa.

Problema: Você deseja controlar sua conta bancária pessoal registrando os saques, depósitos e controlando o saldo da conta.

Conceitos básicos – Herança

A herança é o método de programação usada para implementar a relação é-um (is-a) de um projeto orientado a objetos. Dessa forma, temos que um Botão é-um controle, um Cão é-um mamífero, uma conta de Poupança é-uma conta bancária, etc.

Nota: Você não deve confundir herança com composição que modela um relacionamento tem-um (has-a) entre um objeto e suas propriedades. Assim, um Botão tem-um título, um Cão tem-um nome, uma conta de Poupança tem-um saldo etc.

A herança permite criar classes a partir de classes existentes. Podemos criar novas classes a partir de uma classe base. Neste caso, podemos dizer que a classe derivada herda ou deriva da classe base. Outra terminologia comum usa superclasse para a classe base e subclasse para a classe derivada.

Definindo a classe base

Para a nossa aplicação de controle bancário pessoal, vamos criar uma classe base chamada Conta.

Quando você pensa em uma conta bancária o que lhe vem a mente? O dono da conta (titular), o saldo, o número (ID), os valores a débito (saques) e a crédito (depósitos) etc. Dessa forma podemos identificar os seguintes membros:

Membro Descrição
Titular Uma propriedade string que identifica o titular da conta
ID Uma propriedade string somente-leitura que identifica a conta
Saldo Uma propriedade decimal somente-leitura. O valor dessa propriedade depende dos depósitos e saques feitos na conta.
Deposito Método que usa um parâmetro : o valor depositado. Ele retorna o saldo após o deposito.
Saque Método que usa um parâmetro : o valor do saque. Ele retorna o saldo após o saque.

Construindo o projeto

Abra o Visual Studio 2012 Express for desktop e clique em New Project. Selecione o template: Visual Basic -> Windows -> Windows Forms Application.

Informe o nome ControleBancario e clique no botão OK:

vbn_oop31

A seguir, vamos incluir os seguintes controles no formulário form1.vb:

  • 2 GroupBox – Deposito (R$) e Saque (R$)
  • 2 Label – Valor
  • 2 TextBox – txtValorDeposito e txtValorSaque
  • 2 Button – btnDepositar e btnSacar
  • 1 Label – Saldo da Conta (R$)
  • 1 Label – lblSaldo

O leiaute do formulário é visto abaixo:

vbn_oop34

Criando a classe base, as propriedades, métodos e o construtor da classe base

No menu PROJECT clique em Add Class.. Selecione o template Class e informe o nome Conta.vb e clique em Add:

vbn_oop33

1. Definindo as propriedades e o construtor da classe base

Vamos iniciar definindo as propriedades ID e Saldo da conta e o construtor da classe. Essas propriedades são somente-leitura, indicando que elas não podem ser alteradas; somente lidas.

  • O ID da conta será definido com base no nome do titular da conta. Dessa forma, deveremos ter apenas uma única conta por titular, onde os nomes devem ser únicos. Assim, o ID da conta é o nome do titular da mesma;
  • O saldo da conta é uma propriedade somente-leitura que será alterada pelos depósitos e saques feitos na conta. O saldo será armazenada em um campo do tipo decimal;
  • O construtor da classe irá usar um parâmetro: o nome do titular da conta, visto que toda conta deve possuir um ID. Vamos definir também o valor do campo saldo como igual a zero.

Abaixo temos o código definido na classe Conta:

Public Class Conta

    Private _titular As String
    Public ReadOnly Property ID() As String
        Get
            Return _titular
        End Get
    End Property

    Private _saldo As Decimal
    Public ReadOnly Property Saldo() As Decimal
        Get
            Return _saldo
        End Get
    End Property

    Public Sub New(ByVal titular As String)
        _titular = titular
        _saldo = 0D
    End Sub

End Class

Eu estou usando a sintaxe anterior a versão 4.0 para que o código seja compatível com as versões anteriores.
Para ver a nova sintaxe veja o meu artigo sobre propriedades auto-implementadas: VS2010 – VB .NET – Novos Recursos.

2. Definindo os métodos da classe base

Agora vamos definir os métodos Deposito e Saque da classe base usando a seguinte lógica:

  • Deposito – Este método adiciona um valor ao saldo e retorna o novo saldo;
  • Saque – Este método subtrai um valor do saldo e retorna o novo saldo.

Inclua na classe Conta o código para os métodos conforme abaixo:

 Public Function Deposito(ByVal valor As Decimal) As Decimal
        _saldo += valor
        Return _saldo
    End Function

    Public Function Saque(ByVal valor As Decimal) As Decimal
        _saldo -= valor
        Return _saldo
    End Function

Usando a classe Conta no projeto Windows Forms

Vamos agora testar a nossa classe Conta, realizando saques e depósitos e obtendo o saldo em nosso projeto Windows Forms.

A primeira coisa que temos que fazer e criar uma instância da classe Conta no início do formulário form1.vb: Dim contaMacoratti As New Conta(“Macoratti”)

O código acima defina o objeto ContaMacoratti, usando o construtor da classe Conta com o parâmetro “Macoratti”, que é o nome do titular e passa a ser o ID da conta.

Após isso, podemos exibir o saldo da conta ContaMacoratti. Então no evento Load do formulário vamos chamar a rotina atualizaSaldo() que exibe o saldo atualizado:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        atualizaSaldo()
    End Sub

O código da rotina atualizaSaldo() é dado a seguir:

 Private Sub atualizaSaldo()
        lblSaldo.Text = contaMacoratti.Saldo
    End Sub

O código exibe o valor do saldo na label lblSaldo.Text. Quando iniciarmos o projeto, o construtor inicia o valor do saldo com zero; e o valor exibido será sempre zero no início do programa.

A seguir, podemos definir o código do botão Depositar, que irá realizar depósitos na conta no evento Click do botão de comando:

Private Sub btnDepositar_Click(sender As Object, e As EventArgs) Handles btnDepositar.Click
        Dim valor As Decimal = 0D

        If String.IsNullOrEmpty(txtValorDeposito.Text) Then
            MessageBox.Show("Informe um valor para depósito!")
        Else
            valor = Convert.ToDecimal(txtValorDeposito.Text)
            contaMacoratti.Deposito(valor)
            atualizaSaldo()
        End If
    End Sub

Definimos a variável valor como Decimal e iniciamos o seu valor com zero (0D): Dim valor As Decimal = 0D.

Verificamos se o valor informado no TextBox txtValorDeposito.Text pelo usuário é nulo ou vazio e avisamos o usuário: String.IsNullOrEmpty(txtValorDeposito.Text).

Quando o usuário informar um valor no TextBox, iremos converter o valor informado para Decimal usando o método ToDecimal da classe Convert : valor = Convert.ToDecimal(txtValorDeposito.Text).

Chamamos o método Deposito da classe com o valor informado: contaMacoratti.Deposito(valor) e chamamos a rotina para exibir o saldo atualizado : atualizaSaldo().

De forma a permitir somente valores válidos no TextBox txtValorDeposito.Text, vamos usar o evento KeyPress e permitir somente valores numéricos, o ponto e a vírgula:

Private Sub txtValorDeposito_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtValorDeposito.KeyPress
        If Not Char.IsNumber(e.KeyChar) And Not e.KeyChar = vbBack And Not e.KeyChar = "." And Not e.KeyChar = "," Then
            e.Handled = True
        End If
    End Sub

Neste momento, já podemos executar a aplicação e realizar depósitos:

Fig 1.0 - Janela inicial do projeto
Fig 1.0 – Janela inicial do projeto
Fig 2.0 - Feito um depósito de 100
Fig 2.0 – Feito um depósito de 100

Na janela inicial teremos o saldo da conta exibido como valor zero e podemos digitar um valor e realizar um depósito. Informando o valor 100 e clicando no botão Depositar, teremos o saldo atualizado para 100.

Vamos agora definir o código do botão Sacar, que deverá usar o método Saque da classe Conta e decrementar o saldo do valor informado. Abaixo, vemos o código do evento Click do botão Sacar:

Private Sub btnSacar_Click(sender As Object, e As EventArgs) Handles btnSacar.Click
        Dim valor As Decimal = 0D

        If String.IsNullOrEmpty(txtValorSaque.Text) Then
            MessageBox.Show("Informe um valor para Saque!")
        Else
            valor = Convert.ToDecimal(txtValorSaque.Text)
            contaMacoratti.Saque(valor)
            atualizaSaldo()
        End If
    End Sub

O código é idêntico ao do botão depositar. A única exceção é que chamamos o método Saque da classe conta com o valor informado: contaMacoratti.Saque(valor).

De forma a permitir somente valores válidos no TextBox txtValorSaque.Text, vamos usar o evento KeyPress e permitir somente valores numéricos, o ponto e a vírgula:

Private Sub txtValorSaque_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtValorSaque.KeyPress
        If Not Char.IsNumber(e.KeyChar) And Not e.KeyChar = vbBack And Not e.KeyChar = "." And Not e.KeyChar = "," Then
            e.Handled = True
        End If
    End Sub

Após realizarmos dois depósitos no valor de R$ 100,00 e um saque no valor de R$ 50,00, teremos o resultado abaixo:

vbn_oop37

Se espiarmos a classe conta no Class View (Menu VIEW-> Class View) iremos obter:

vbn_oop38

Criando uma classe derivada da classe base

Vamos agora criar uma nova classe chamada Poupanca, que deverá ser uma classe derivada da nossa classe base Conta.

Quando você estende uma classe para criar uma nova, essa nova classe estendida herda todas as propriedades e métodos da classe original, que é conhecida como superclasse, classe pai ou classe base; a classe que originada é conhecida como classe filha ou subclasse – se a classe filha não sobrepõe(overrides) nenhum procedimento da classe pai, ela herda todo o comportamento da classe pai).

Algumas das características importantes sobre herança no VB.NET são:

  • A declaração Inherits implementa a herança no VB.NET;
  • O VB.NET permite somente herança simples, ou seja , as classes derivadas podem ter somente uma única classe pai ou classe base;
  • Qualquer classe declarada por ser herdada. Para impedir que uma classe possa ser herdada, você deve usar o modificar NoInheritable em sua declaração;
  • No VB.NET tudo são classes e todas as classes são herdadas de outras classes. Logo, todas elas derivam da classe-raiz simples chamada System.Object. Quando você declara uma classe sem especificar herança, ela herda implicitamente da classe System.Object;
  • Uma classe pública (Public) não pode herdar uma classe privada (Private) ; uma classe amigável (Friend) não pode herdar uma classe (Private);
  • O VB.NET utiliza a palavra chave MyBase para se referir aos membros da classe base em uma classe derivada.

A classe Poupanca é idêntica a classe Conta exceto em relação aos seguintes aspectos:

  • A conta de poupança rende juros, portanto a classe terá uma propriedade adicional chamada Juros;
  • A conta de poupança pode acumular juros ao longo do tempo, logo a classe terá um método adicional chamado AdicionarJuros;
  • Uma pessoa pode ter uma conta de poupança e uma conta corrente. Para distinguir entre a duas contas, a propriedade ID deverá indicar o tipo de conta.

Vamos criar a classe Poupança, herdando da classe Conta. Para isso vamos usar a palavra-chave Inherits. No menu PROJECT clique em Add Class, selecione o templateClass e informe o nome Poupanca.vb.

A seguir digite o código abaixo nesta classe:

vbn_oop39

Note que o compilador emite uma mensagem de erro:

Error 1 Class ‘ControleBancario.Poupanca’ must declare a ‘Sub New’ because its base class ‘ControleBancario.Conta’
does not have an accessible ‘Sub New’ that can be called with no arguments.

Numa tradução livre: A classe ‘ControleBancario.Poupanca’ deve declarar um ‘Sub New’ pois classe base ‘ControleBancario.Conta’ não tem um Sub New acessível que pode ser chamado sem argumentos.

O erro indica que temos que declarar um construtor para a classe Poupanca, pois o construtor da classe Conta não esta acessível. Os construtores não são herdados; portanto, você deve adicioná-los na classe derivada. Além disso, sempre que um construtor é definido, ele inclui uma chamada implícita para o construtor sem parâmetros que pertence à classe base.

Na classe Conta, criamos somente um único construtor público que possui um parâmetro para o nome do titular da conta. Como o construtor sem parâmetros não existe na classe base, temos que fazer uma chamada explicita ao construtor. Logo temos que incluir esse construtor na classe Poupanca.

Vamos corrigir o erro digitando o código abaixo:

vbn_oop3a

Este código introduz a palavra-chave MyBase, que se refere à classe base da classe derivada. No caso do construtor, não há sentido em reescrever o código que você escreveu na classe base Conta. Uma chamada para a classe base é suficiente: MyBase.New().

Vamos agora pensar um pouco sobre as propriedades da classe Poupanca. Começando pela propriedade ID, que deverá identificar a conta de poupança. Ela faz isso usando o nome do titular acrescentando o sufixo -P. Assim, o titular da conta com o nomeMacoratti será identificado na conta de poupança como Macoratti-P.

Para implementar isso na classe Poupanca teremos que modificar a propriedade ID que está sendo herdada da classe Conta pela classe Poupanca, sobrescrevendo o seu comportamento.

Para poder sobrescrever o seu comportamento, usamos o modificador overrides na classe derivada, conforme mostramos a seguir:

vbn_oop3b

Observe que o compilador reporta um erro, indicando que para podermos sobrescrever a propriedade ID na classe derivada temos que declará-la como Overridable na classe base. Então, retorne a classe base Conta e altere o modificar da propriedade ID:

Public Overridable ReadOnly Property ID() As String
        Get
            Return _titular
        End Get
    End Property

Agora podemos retornar à classe Poupanca e terminar a implementação da propriedade ID:

vbn_oop3c

Agora temos outro erro: O compilador indica que o membro _titular da classe base não esta acessível. Lembre que o membro _titular foi definido como Private e por isso está visível somente na classe de origem. Para resolver esse erro, temos que alterar o modificador do membro _titular de Private para Protected na classe Conta:

Protected _titular As String
    Public Overridable ReadOnly Property ID() As String
        Get
            Return _titular
        End Get
    End Property

Com isso, o erro será revolvido visto que modificador Protected torna a variável de uma classe base somente acessível as suas classes derivadas. O código final na classe Poupanca da propriedade ID ficou assim:

 Public Overrides ReadOnly Property ID() As String
        Get
            Return Me._titular + "-P"
        End Get
    End Property

Este código apresenta a palavras-chave Me, que refere-se a instância de classe. Neste caso, utilizar Me não é obrigatório; poderíamos digitar apenas _titular.

Você pode usar a palavra-chave Me em situações em que você pode ter conflitos com nomes de variáveis. Talvez você tenha o mesmo campo declarado na classe e no método, neste caso a palavra-chave Me indica qual variável você deve usar.

Vamos agora definir a propriedade Juros na classe derivada Poupanca, conforme o código abaixo:

Private _juros As Decimal = 0.01
    Public Property Juros() As Decimal
        Get
            Return _juros
        End Get
        Set(ByVal Value As Decimal)
            _juros = Value
        End Set
 End Property

Esta propriedade foi definida com um valor inicial :Private _juros As Decimal = 0.01. Agora crie o método AdicionarJuros na classe Poupanca conforme o código a seguir:

Public Function AdiconarJuros() As Decimal
        Me.Deposito(_juros * Me.Saldo)
        Return Me.Saldo
End Function

O código acima usa o método Deposito da classe base para incluir o valor do saldo atual acrescidos dos juros usando a propriedade Saldo.

Como campo _saldo foi definido como Private na classe base Conta e a propriedade Saldo é somente-leitura, a única maneira de adicionar dinheiro na conta é, por definição, através do método Deposito.

Testando a classe Poupança no projeto Windows Forms

Para podermos testar a nova classe Poupanca que foi derivada da classe base Conta em nosso projeto Windows Forms, vamos ter que ajustar o formulário para permitir que o usuário escolha depositar e sacar na conta ou na poupança e também permitir que o usuário defina uma taxa de juros e adicione o juros calculado na conta de poupança.

No início do formulário, vamos criar uma instância da classe Poupanca: Dim contaPoupancaMacoratti As New Poupanca(“Macoratti”). Dessa forma, poderemos usar o objeto contaPoupancaMacoratti com a respectiva conta de poupança criada com nome do titular – Macoratti.

Agora vamos ajustar o formulário. Abra o formulário form1.vb do projeto e inclua os seguintes controles a partir da Toolbox:

  • 2 RadioButtons – rdbDepositoConta e rdbDepositoPoupanca
  • 2 RadioButtons – rdbSaqueConta e rdbSaquePoupanca
  • GroupBox – Poupança – Juros
  • TextBox – txtJurosPoupanca
  • Button – btnAdicionarJurosPoupanca
  • Label – Saldo da Poupança (R$)
  • Label – lblSaldoPoupanca

Disponha os controles conforme o leiaute da figura abaixo:

vbn_oop3d

Vamos alterar o código dos botões Depositar e Sacar para que as operações sejam feitas na conta escolhida pelo usuário selecionando os controles radiobuttons. O código ajustado ficou assim:

Private Sub btnDepositar_Click(sender As Object, e As EventArgs) Handles btnDepositar.Click
        Dim valor As Decimal = 0D

        If String.IsNullOrEmpty(txtValorDeposito.Text) Then
            MessageBox.Show("Informe um valor para depósito!")
        Else
            valor = Convert.ToDecimal(txtValorDeposito.Text)
            If rdbDepositoConta.Checked Then
                contaMacoratti.Deposito(valor)
            ElseIf rdbDepositoPoupanca.Checked Then
                contaPoupancaMacoratti.Deposito(valor)
            End If
            atualizaSaldo()
            End If
    End Sub

 

Private Sub btnSacar_Click(sender As Object, e As EventArgs) Handles btnSacar.Click
        Dim valor As Decimal = 0D

        If String.IsNullOrEmpty(txtValorSaque.Text) Then
            MessageBox.Show("Informe um valor para Saque!")
        Else
            valor = Convert.ToDecimal(txtValorSaque.Text)
            If rdbSaqueConta.Checked Then
                contaMacoratti.Deposito(valor)
            ElseIf rdbSaquePoupanca.Checked Then
                contaPoupancaMacoratti.Deposito(valor)
            End If
            atualizaSaldo()
        End If
    End Sub

Temos que atualizar também a rotina atualizaSaldo de forma a exibir os valores para saldo da conta de poupança.

Private Sub atualizaSaldo()
        lblSaldo.Text = contaMacoratti.Saldo.ToString("C")
        lblSaldoPoupanca.Text = contaPoupancaMacoratti.Saldo.ToString("C")
    End Sub

No código eu estou usando a instância da classe Poupanca – contaPoupancaMacoratti – e exibindo o saldo através da propriedade Saldo.

Note que estou formatando o resultado usando ToString(“C”), que formata a saída no formato da moeda local.(R$).

Finalmente vamos definir o código para adicionar os juros ao saldo da poupança usando o evento Click do botão – Adicionar Juros na Conta de Poupança:

Private Sub btnAdicionarJurosPoupanca_Click(sender As Object, e As EventArgs) Handles btnAdicionarJurosPoupanca.Click
        Dim taxaJuros As Decimal = 0D
        taxaJuros = Convert.ToDecimal(txtJurosPoupanca.Text)
        If taxaJuros <> 0 Then
            'define o valor da taxa de juros na classe de poupança
            contaPoupancaMacoratti.Juros = taxaJuros
        End If
        'inclui os juros na conta de poupança
        contaPoupancaMacoratti.AdicionarJuros()
        atualizaSaldo()
    End Sub

Estamos convertendo o valor informado pelo usuário no TextBox -txtJurosPoupanca. Se o valor informado for igual a zero, estamos atualizando o valor da propriedade Juros. Caso contrário, usaremos o valor padrão atribuído na propriedade.

Depois usamos o método AdicionarJuros() do objeto contaPoupancaMacoratti, que é uma instância da classe Poupanca.

Executando o projeto e realizando um depósito e adicionando os juros na poupança teremos:

vbn_oop3e

Para concluir esta parte, vamos exibir também o nome do titular da conta e da poupança alterando a rotina atualizaSaldo:

Private Sub atualizaSaldo()
        lblTitularConta.Text = contaMacoratti.ID
        lblSaldo.Text = contaMacoratti.Saldo.ToString("C")
        lblTitularPoupanca.Text = contaPoupancaMacoratti.ID
        lblSaldoPoupanca.Text = contaPoupancaMacoratti.Saldo.ToString("C")
    End Sub

Note que usamos a propriedade ID da classe base (contaMacoratti.ID) e da classe derivada (contaPoupancaMacoratti.ID) , que sobrescreveu o método da classe base:

Executando o projeto novamente e realizando algumas operações temos:

vbn_oop3f

Pegue o projeto completo aqui: ControleBancario.zip

Na próxima aula irei mostrar os conceitos das classes abstratas e sua criação e testar a aplicação.