VB .NET - Programação Orientada a Objetos (em 10 lições práticas) - VI


VB .NET é uma linguagem orientada a objetos.

Até o momento apresentamos os conceitos da programação orientada a objetos afetos à linguagem VB .NET usando uma aplicação bem simples de controle de saldos bancários onde definimos uma classe base Conta e uma classe Poupanca que herda dessa classe base. Vimos como criar métodos e propriedades na classe base e como especializar essa classe criando classes derivadas. Vimos assim como usar os recursos da herança, sobrescrever um método e como interagir como controles de formulários em uma aplicação Windows Forms.

Neste artigo vamos definir uma interface e mostrar como podemos usar os seus recursos em nossa aplicação bancária.

- Definindo e usando uma Interface - VI

Nesta aplicação você vai aprender a :

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 : http://www.microsoft.com/visualstudio/eng/2013-downloads

É importante salientar que a ferramenta usada é gratuita, não possui restrições sendo totalmente funcional. Ao fazer o download da ferramenta você também pode baixar o pacote de idioma 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 usando os conceitos da programação orientada a objetos da linguagem VB .NET.

Conceitos Básicos - Interfaces

Vamos pensar um pouco sobre o que fizemos até agora. Criamos uma classe base Conta a partir da qual criamos a classe derivada Poupanca. Temos assim duas classes concretas : a classe Conta e a classe Poupanca.

Se pensarmos em um banco do mundo real(lembre-se que classes devem modelar o mundo real) iremos constatar que na verdade não podemos abrir uma conta genérica. Muito provavelmente o banco irá nos oferecer um tipo de conta especifico para escolha. Em geral temos a conta corrente, a conta poupança, a conta especial,etc.

Dessa forma a nossa classe Conta deveria definir o comportamento comum de um conta genérica mesmo que nunca fossemos criar uma conta desse tipo.

Criamos então uma classe base Conta abstrata e nessa classe definimos apenas o comportamento comum a uma conta genérica implementando alguns métodos e deixando outros como métodos abstratos.

Outra alternativa seria criar uma interface ao invés de uma classe abstrata.

Mas o que vem a ser uma interface ?

Uma interface, no paradigma da orientação a objetos, é  um tipo de classe que contém apenas as assinaturas de métodos, propriedades, eventos e indexadores.

A implementação dos membros é feita por uma classe concreta ou estrutura (struct) que implementa os métodos da interface.

Uma interface nunca pode ser instanciada e contém somente as assinaturas dos métodos, não possuindo construtores nem campos, sendo que seus membros são sempre públicos e não podem ser declarados como estáticos (static) nem como overridable, ou seja, os métodos não podem ser sobrepostos e sim devem ser implementados.

Uma interface é parecida com uma classe abstrata; a diferença é que uma classe abstrata pode possuir métodos que não estejam implementados e pode possuir métodos que estejam implementados.

Como o VB.NET não suporta herança múltipla as interfaces permitem que uma classe estenda múltiplas interfaces contornando o problema (se é que isto é um problema ). Para implementar uma interface o VB.NET usamos o modificador - Implements .

As interfaces são declaradas usando a palavra-chave - Interface. Geralmente o nome dado a uma interface começa com a letra I. Podemos ter duas sintaxes para o uso com interfaces:


Interface IForma
End Interface

Class Linha
    Implements IForma 
End Class
Interface IForma
End Interface

Class Linha: Implements IForma
End Class

Podemos então para o nosso exemplo criar uma interface ao invés de uma classe abstrata como fizemos na aula anterior. Podemos criar uma interface para Conta contendo 3 métodos : Depositar(), Sacar() e  Saldo que deverá ser implementada por todo o tipo de conta para usar a interface.

Construindo o projeto

Para tornar o exemplo mais simples e fácil de entender eu não vou criar um projeto Windows Forms como fiz na aula anterior. Vou criar um projeto do tipo Console Application.

Vou definir a interface Conta e mostrar como podemos implementá-la em duas classes concretas : ContaPoupanca e ContaCorrente.

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

Selecione o template : Visual Basic -> Windows -> Console Application

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

Criando a interface Conta

No menu PROJECT clique em Add Class;

Selecione o template Class e informe o nome IConta.vb e clique em Add;

Para definirmos uma interface no VB .NET temos que usar a palavra-chave Interface antes do nome da  interface (IConta) e terminar com a declaração End Interface;

Vamos começar definindo a nossa interface da seguinte com 2 métodos e 1 propriedade:

  1. Saldo() - propriedade somente leitura;
  2. Depositar() - método que permite sacar um valor da conta
  3. Sacar() - método que permite depositar  um valor da conta

Veja como deve ficar o código VB .NET da nossa interface IConta :

Public Interface IConta
    Function Depositar(valor As Decimal) As Boolean
    Function Sacar(valor As Decimal) As Boolean
    ReadOnly Property Saldo() As Decimal
End Interface

Note que temos apenas a declaração da propriedade e dos métodos mas não a sua implementação. A implementação destes membros deverá ser feita pelas classes concretas.

Criando a classe ContaPoupanca e implementando a interface IConta

Vamos criar agora a classe concreta ContaPoupanca.

No menu PROJECT clique em Add Class;

Selecione o template Class e informe o nome ContaPoupanca.vb e clique em Add;

A seguir digite logo abaixo da declaração da classe a palavra Implements e a seguir a interface IConta:

Ao teclar ENTER o Visual Studio irá criar automaticamente os métodos e propriedades da interface que devemos implementar conforme mostra a figura abaixo:

Vamos definir duas variáveis privadas na classe ContaPoupanca:

Private _saldo As Decimal
Private _limiteDiario As Decimal

1- Implementando o método Depositar

Vamos implementar o método Depositar conforme o código abaixo:

  Public Function Depositar(valor As Decimal) As Boolean Implements IConta.Depositar
        _saldo += valor
         Console.WriteLine(String.Format("Deposito realizado com sucesso : {0,6:C}", valor))
        Return True
    End Function

O método Depositar da ContaPoupanca irá incrementar o valor do saldo da conta pelo valor do depósito e retornar um valor igual a True.

2- Implementando o método Sacar

No método Sacar temos que  verificar se existe saldo na conta e se o valor do saque é superior ao limite diário (definido como R$ 1.000,00 ).

Se houver saldo e o valor do saque estiver dentro do valor limite iremos exibir  uma mensagem de saque realizado com sucesso.

A seguir temos a implementação do método Sacar() para a classe ContaPoupanca:

Public Function Sacar(valor As Decimal) As Boolean Implements IConta.Sacar
        If _saldo < valor Then
            Console.WriteLine("Saldo insuficiente.")
            Return False
        ElseIf _limiteDiario + valor > 1000 Then
            Console.WriteLine("Valor superior ao limite diário!")
            Return False
        Else
            _saldo -= valor
            _limiteDiario += valor
            Console.WriteLine(String.Format("Saque realizado com sucesso : {0,6:C}", valor))
            Return True
        End If
    End Function

3- Implementando a propriedade Saldo

A propriedade Saldo apenas permite que o seu valor seja lido não podendo ser alterado diretamente fora da classe.  A isso chamamos encapsulamento. Dessa forma o valor do Saldo somente poderá ser alterado usando os métodos Sacar() e Depositar() da própria classe.

A seguir temos o código da implementação da propriedade Saldo:

 Public ReadOnly Property Saldo As Decimal Implements IConta.Saldo
        Get
            Return _saldo
        End Gil
    End Property

4- Sobrescrevendo o método ToString()

Vamos também sobrescrever o método ToString()  que retorna uma string que representa o objeto atual. Esse método é um método do .NET Framework e como cada classe no VB .NET herda de Object , cada objeto no VB .NET contém o método ToString(). Podemos sobrescrever o método para criar uma mensagem personalizada que desejamos usar em nossa classe.

É isso que fizemos a seguir sobrescrevendo o método ToString() da classe Object:

 Public Overrides Function ToString() As String
      Return  String.Format("Saldo da Conta de Poupança = {0,6:C}", _saldo)
 End Function

E assim temos o código completo da classe ContaPoupanca que implementa os métodos e propriedades da interface IConta:

Public Class ContaPoupanca
  
 Implements IConta

    Private _saldo As Decimal
    Private _limiteDiario As Decimal

    Public Function Depositar(valor As Decimal) As Boolean Implements IConta.Depositar
        _saldo += valor
      
 Console.WriteLine(String.Format("Deposito realizado com sucesso : {0,6:C}", valor))
        Return True
    End Function

    Public Function Sacar(valor As Decimal) As Boolean Implements IConta.Sacar
        If _saldo < valor Then
            Console.WriteLine("Saldo insuficiente.")
            Return False
        ElseIf _limiteDiario + valor > 1000 Then
            Console.WriteLine("Valor superior ao limite diário!")
            Return False
        Else
            _saldo -= valor
            _limiteDiario += valor
            Console.WriteLine(String.Format("Saque realizado com sucesso : {0,6:C}", valor))
            Return True
        End If
    End Function

    Public ReadOnly Property Saldo As Decimal Implements IConta.Saldo
        Get
            Return _saldo
        End Get
    End Property

    Public Overrides Function ToString() As String
        Return String.Format("Saldo da Conta de Poupança = {0,6:C}", Saldo)
    End Function

End Class

Criando a classe ContaCorrente e implementando a interface IConta

Vamos agora criar a classe concreta ContaCorrente.

No menu PROJECT clique em Add Class;

Selecione o template Class e informe o nome ContaCorrente.vb e clique em Add;

A seguir digite logo abaixo da declaração da classe a palavra Implements e a seguir a interface IConta.

Ao teclar ENTER o Visual Studio irá criar automaticamente os métodos e propriedades da interface que devemos implementar conforme mostra a figura abaixo:

Nesta classe vamos definir apenas uma variável privada visto que não teremos valor para limite diário de saque.

Private _saldo As Decimal

1- Implementando o método Depositar

Vamos implementar o método Depositar conforme o código abaixo:

  Public Function Depositar(valor As Decimal) As Boolean Implements IConta.Depositar
        _saldo += valor
         Console.WriteLine(String.Format("Deposito realizado com sucesso : {0,6:C}", valor))
        Return True
    End Function

O método Depositar da ContaCorrente, da mesma forma que a classe ContaPoupanca , irá incrementar o valor do saldo da conta pelo valor do depósito e retornar um valor igual a True e uma mensagem de depósito feito com sucesso.

2- Implementando o método Sacar

No método Sacar temos que  verificar apenas se existe saldo na conta.

Se houver saldo iremos exibir  uma mensagem de saque realizado com sucesso caso contrário iremos exibir saldo insuficiente.

A seguir temos a implementação do método Sacar() para a classe ContaPoupanca:

Public Function Sacar(valor As Decimal) As Boolean Implements IConta.Sacar
        If _saldo < valor Then
            Console.WriteLine("Saldo insuficiente.")
            Return False
        Else
            _saldo -= valor
            Console.WriteLine(String.Format("Saque realizado com sucesso : {0,6:C}", valor))
            Return True
        End If
 End Function

3- Implementando a propriedade Saldo

A seguir temos o código da implementação da propriedade Saldo que é idêntico ao da classe ContaPoupanca:

 Public ReadOnly Property Saldo As Decimal Implements IConta.Saldo
        Get
            Return _saldo
        End Gil
    End Property

4- Sobrescrevendo o método ToString()

Nesta classe também vamos sobrescrever o método ToString() igual a classe ContaPoupanca apenas alterando a mensagem :

 Public Overrides Function ToString() As String
      Return [String].Format("Saldo da Conta Corrente = {0,6:C}", _saldo)
 End Function

E assim temos o código completo da classe ContaCorrente que implementa os métodos e propriedades da interface IConta:

Public Class ContaCorrente
    Implements IConta
    Private _saldo As Decimal
    Public Function Depositar(valor As Decimal) As Boolean Implements IConta.Depositar
        _saldo += valor
         Console.WriteLine(String.Format("Deposito realizado com sucesso : {0,6:C}", valor))
        Return True
    End Function
    Public Function Sacar(valor As Decimal) As Boolean Implements IConta.Sacar
        If _saldo < valor Then
            Console.WriteLine("Saldo insuficiente.")
            Return False
        Else
            _saldo -= valor
            Console.WriteLine(String.Format("Saque realizado com sucesso : {0,6:C}", valor))
            Return True
        End If
    End Function
    Public ReadOnly Property Saldo As Decimal Implements IConta.Saldo
        Get
            Return _saldo
        End Get
    End Property
    Public Overrides Function ToString() As String
        Return String.Format("Saldo da Conta Corrente = {0,6:C}", Saldo)
    End Function
End Class

Testando as classes no projeto Console Application

Vamos agora testar a utilização da interface e das classes criadas no projeto em uma aplicação Console Application.

Vamos criar uma instância da classe ContaPoupanca e da classe ContaCorrente e realizar algumas operações de saque e deposito.

O código deverá ser incluído no arquivo Module1.vb conforme abaixo:

Module Module1
    Sub Main()
        'criando as instãncias das Classes Concretas como sendo do tipo da Interface IConta
        Dim contaPoupanca_Macoratti As IConta = New ContaPoupanca()
        Dim contaCorrente_Macoratti As IConta = New ContaCorrente()
        Console.WriteLine("Testando a conta de poupança." & vbCrLf)
        contaPoupanca_Macoratti.Depositar(2000)
        contaPoupanca_Macoratti.Sacar(100)
        contaPoupanca_Macoratti.Sacar(1000)
        contaPoupanca_Macoratti.Sacar(200)
        Console.WriteLine(contaPoupanca_Macoratti.ToString())
        Console.ReadKey()
        Console.WriteLine("Testando a conta corrente." & vbCrLf)
        contaCorrente_Macoratti.Depositar(3000)
        contaCorrente_Macoratti.Sacar(150)
        contaCorrente_Macoratti.Sacar(1000)
        contaCorrente_Macoratti.Sacar(90)
        contaCorrente_Macoratti.ToString()
        Console.WriteLine(contaCorrente_Macoratti.ToString())
        Console.ReadKey()
    End Sub
End Module

Executando o projeto iremos obter o seguinte resultado:

Abaixo vemos exemplos de execução para Poupanca e ContaCorrente:

Vimos assim como podemos criar uma interface e implementar seus métodos em classes concretas.

Nesse momento você pode estar com as seguintes dúvidas:

Quando você deve usar uma classe abstrata ? 

Quando você deve usar uma Interface ?

Quando você deve usar as duas ?

A seguir um pequeno roteiro para ajudá-lo a tomar a melhor decisão ....

O que é uma classe abstrata ?

Suponha que vamos criar várias classes que têm métodos em comum e outros métodos funcionam diferente para cada classe. Uma forma de fazer isso é usar as classes abstratas.

- As classes abstratas tem pelo menos um método abstrato, ou seja um método que não tem corpo.
- Se um método tem uma classe abstrata ele deve ser declarado como um método abstrato.
- Não podem ser criadas instâncias de classes abstratas.
- Ao criar uma classe usando uma classe abstrata como herança devem ser criados os corpos para os métodos abstratos.
- Para criar uma classe usando uma classe abstrata como herança basta usar a palavra-chave inherits , como em uma classe normal
- Um método abstrato é identificado pelo modificador - MustOverride - , a classe que possui este modificador não pode ser instanciada através da palavra chave New. Vamos a um exemplo:

O que são Interfaces ?

Interfaces podem ser entendidas como um tipo de classe abstrata em que todos métodos são abstratos.

- Em uma interface nenhum método tem corpo e são implicitamente abstratas e publicas
- Assim como uma classe abstrata , uma interface não pode ser instanciada.
- Uma classe pode implementar mais de uma interface
- Uma interface não pode conter um construtor
- Ao criar uma classe usando uma interface devem ser feitos os corpos de todos os métodos da interface, caso contrario deverá ser criada uma classe abstrata.
- Para implementar uma interface no VB.NET usamos o modificador - Implements .

Com os conceitos bem definidos vamos tentar uma tabela de consulta rápido para tomada de decisões:

Interfaces      x     Classes Abstratas
Característica Interface Classe Abstrata
Herança múltipla Uma classe pode implementar diversas interfaces Uma classe pode herdar  somente uma classe
Implementação Padrão Uma interface não pode conter qualquer tipo de código, muito menos código padrão. Uma classe abstrata pode fornecer código completo , código padrão ou ter apenas a declaração de seu esqueleto para ser posteriormente sobrescrita.
Constantes Suporte somente constantes do tipo estática. Pode conter constantes estáticas e de instância.
Componentes de terceiros Uma implementação de uma interface pode ser incluída a qualquer classe de terceiros. Uma classe de terceiros precisa ser reescrita para estender somente a partir da classe abstrata.
Homogeneidade Se todas as diversas implementações compartilham a assinatura do método então a interface funciona melhor. Se as várias implementações são todas do tipo e compartilham um comportamento e status comum , então a classe abstrata funciona melhor.
Manutenção Se o código do seu cliente conversa somente em termos de uma interface, você pode facilmente alterar a implementação concreta usando  um método factory. idêntico
Velocidade Lento , requer trabalho extra para encontrar o método correspondente na classe atual. Rápido
Clareza Todas as declarações de constantes em uma interface são presumidamente publicas ou estáticas. Você pode por código compartilhado em uma classe abstrata. Você pode usar código para computar o valor inicial de suas constantes e variáveis de instância ou estáticas.
Funcionalidades Adicionais Se você incluir um novo método em uma interface você precisa ajustar todas as implementações da interface. Se você incluir um novo método em uma classe abstrata você tem a opção de fornecer uma implementação padrão para ele.

Você decide. !

Pegue o projeto completo aqui: OOP_Interface.zip

Na próxima aula irei abordar os conceitos sobre polimorfismo e sua implementação e utilização na linguagem Visual Basic.

Referências:


José Carlos Macoratti