.NET - Programação Orientada a Objetos x Programação Procedural


Neste artigo eu vou tratar mais um vez dos conceitos da programação orientada a objetos (OO) e da programação procedural mostrando as diferenças entre ambas procurando usar uma linguagem simples e objetiva.

O termo Programação procedural (ou programação procedimental) é às vezes utilizado como sinônimo de Programação imperativa (Paradigma de programação que especifica os passos que um programa deve seguir para alcançar um estado desejado), mas o termo pode se referir a um paradigma de programação baseado no conceito de chamadas a procedimento.

Procedimentos, também conhecidos como rotinas, sub-rotinas, métodos, ou funções simplesmente contém um conjunto de passos computacionais a serem executados. Um dado procedimento pode ser chamado a qualquer hora durante a execução de um programa, inclusive por outros procedimentos ou por si mesmo.
fonte : http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_procedural (acessado em abril de 2014)

O que é exatamente um objeto ?

É uma questão complexa e simples ao mesmo tempo.
Complexa porque o aprendizado de qualquer método de desenvolvimento de software não é trivial.
Simples porque as pessoas já pensam em termos de objetos.

Quando você olha para uma pessoa você vê a pessoa como um objeto, e um objeto é definido por dois termos: atributos e comportamento.

Uma pessoa tem atributos como olhos, cor, idade, altura, peso, etc.
Uma pessoa possui comportamentos como caminhar, falar, respirar, etc.
Em uma definição básica um objeto é uma entidade que contém dados e comportamento.

A palavra 'e'  é a chave para diferenciar a programação orientada a objetos e outras metodologias de programação.

Na programação procedural, por exemplo, o código é colocado em funções ou procedimentos totalmente distintos.

Assim, esses procedimentos tornam-se caixas pretas onde temos a entrada e a saída do resultado. Os dados são colocados em estruturas separadas e é manipulado por essas funções ou procedimentos.

OOP x Procedural

No projeto OO os atributos e comportamentos estão contidos dentro de um único objeto, ao passo que no projeto procedural ou estruturado, os atributos e comportamentos estão normalmente separados.

Como ilustrado na figura abaixo, na programação estruturada os dados são frequentemente separados dos procedimentos e as algumas vezes os dados são globais, sendo assim muito fácil modificar os dados de fora do escopo do seu código.

A consequência disso é que o acesso aos dados é descontrolado e imprevisível (isto é, várias funções podem ter acesso aos dados globais). E como você não tem controle sobre quem tem acesso aos dados, testar e depurar o seu código será muito difícil.

A programação orientada a objetos (OO) resolve esse problema através da combinação de dados e comportamento em um pacote completo.

Apenas para ilustrar, abaixo temos uma tabela comparando as características básicas do paradigma OO e do procedural:

Programação Orientada a Objetos Programação Estruturada
Métodos Procedimentos e funções
Instâncias de variáveis Variáveis
Mensagens Chamadas a procedimentos e funções
Classes Tipos de dados definidos pelo usuário
Herança não disponível
Polimorfismo não disponível

O projeto adequado

Podemos afirmar que quando projetado adequadamente não existem dados globais em um modelo da programação orientada a objetos. Este fato fornece uma grande integridade aos dados em sistemas OO.

Programas estruturados possuem uma estrutura complexa de dados como arrays, inteiros, strings, etc., mas objetos são muito mais do que estruturas e tipos de dados primitivos como inteiros e strings.Embora objetos possam conter entidades como inteiros e strings, os quais são usados para representar atributos, eles também contém métodos que representam comportamentos.

Na terminologia OO, os dados são referidos como atributos e os comportamentos referidos como métodos.

Em um objeto, métodos são usados para realizar operações nos dados bem como outras ações. O mais importante disso é que você pode controlar o acesso aos membros de um objeto (aos atributos e métodos). Isso significa que alguns membros, os atributos e métodos podem ser escondidos de outros objetos.

Restringir o acesso a determinados atributos e/ou métodos é chamado de ocultamento de dados.(data hiding)

Pela combinação de atributos e métodos na mesma entidade, que na terminologia OO é chamada de encapsulamento, podemos controlar o acesso aos dados de um objeto.

Como exemplo vamos definir o objeto chamado Calculadora que contém dois inteiros int1 e int2 e que também contém métodos para atribuir e retornar os valores de int1 e int2. Além disso esse objeto contém um método chamado Soma() que é usado para somar esses dois inteiros.

O que ocorre quando outro objeto chamado MeuObjeto quer acessar a soma de int1 com int2 ?

Ele envia uma mensagem ao objeto Calculadora.

A figura abaixo mostra como os dois objetos se comunicam entre si através de seus métodos.

A mensagem é na verdade uma chamada ao método Soma() do objeto Calculadora. O método Soma() então retorna o valor para MeuObjeto.

A beleza disto é que MeuObjeto não precisa saber como a soma é calculada.

Com essa metodologia de projeto você pode alterar como o objeto Calculadora calcula a soma sem ter que fazer qualquer alteração em MeuObjeto. Você quer apenas a soma e não se importa como ela é calculada.

Usando uma simples calculadora para ilustrar o conceito, quando você realiza a soma com uma calculadora tudo o que você usa é a interface da calculadora, o teclado e os leds do painel de exibição dos números.A calculadora possui um método Soma() que é invocado quando você pressiona as teclas corretas para obter o resultado correto, porém você não tem ideia de como o resultado foi obtido.

Calcular a soma não é responsabilidade de MeuObjeto, é responsabilidade do objeto Calculadora.

Tão logo MeuObjeto tenha acesso ao objeto Calculadora, ele pode enviar as mensagens apropriadas e obter o resultado pertinente.

Em geral objetos não manipulam dados internos de outros objetos ou seja MeuObjeto não pode alterar diretamente o valor de int1 e int2.

Programação Procedural

A programação procedural normalmente separa os dados do sistema das operações que manipulam os dados. Por exemplo se você quer enviar uma informação através da rede, somente os dados relevantes são enviados com a expectativa que outro programa que vai receber os dados na rede saiba o que fazer com os dados.

Em outras palavras, um espécie de acordo precisa existir entre o cliente e o servidor para transmitir os dados.

Programação Orientada a Objetos

A vantagem fundamental da OO é que os dados e as operações que manipulam os dados (o código) estão ambos encapsulados no objeto.

Por exemplo, quando um objeto é transportado através de um rede, o objeto inteiro, incluindo os dados e o comportamento vai junto com ele.

O que é exatamente uma classe ?

Na programação OO usamos os objetos seus atributos e comportamentos, mas de onde vêm os objetos ? a partir do que são gerados ?

Uma classe é um modelo para um objeto.

Quando você instancia um objeto você usa uma classe como base para construir o objeto.

É difícil descrever uma classe sem usar o termo objeto e vice-versa.

Assim a classe tem que existir primeiro pois um objeto não pode ser instanciado sem uma classe.

Classes são modelos para objetos

As classes podem ser vistas como modelos para objetos. Um modelo é como um molde a partir do qual podemos criar diversos objetos.

Na figura abaixo temos um exemplo onde a classe Estrela funciona como um modelo para criar objetos Estrela:

Lembre-se que cada objeto tem seus próprios atributos (campos) e comportamentos (funções e rotinas). Uma classe define os atributos e comportamentos que todos os objetos criados a partir dela irão possuir.

Dessa forma classes são pedaços de código, e os objetos instanciados a partir de classes podem ser distribuídos individualmente ou como parte da biblioteca.

Como os objetos são criados a partir de classes, temos que as classes precisam definir os fundamentos básicos da construção de objetos (atributos, comportamentos e mensagens).

Assim temos que projetar a classe antes de criar seus objetos.

Apenas para mostrar um exemplo com código abaixo temos um exemplo de uma classe Pessoa que tanto pode ser usado com C# como com Java:

    public class Pessoa
    {
        //Atributos
        private String nome;
        private String endereco;
        //Metodos
        public String getNome()
        {
            return nome;
        }
        public void setName(String _nome)
        {
            nome = _nome;
        }
        public String getEndereco()
        {
            return endereco;
        }
        public void setEndereco(String _endereco)
        {
            endereco = _endereco;
        }
    }

Na classe Pessoa os atributos são representados por nome e endereco.

Quando um tipo de dados ou método é definido como Public outros objetos podem acessá-los diretamente.

Quando um tipo de dados ou método é definido como Private o acesso a eles é restrito.

Na classe Pessoa os comportamentos (métodos) getNome(), setNome(), getEndereco() e setEndereco() foram definidos como Public permitindo que outros objetos inspecionem e alterem os valores dos atributos do objeto.

Atualmente usamos a linguagem UML - Unified Modeling Language - para modelar um projeto de software OO, e na UML, o usamos o diagrama de classes para ilustrar as classes que projetamos.

Abaixo vemos o diagrama da classe Pessoa que criamos acima:

O retângulo é o desenho que representa a classe e ele esta dividido em três áreas :

1- A parte superior contém o nome da classe
2- A parte do meio contém os atributos da classe
3- A parte de baixo contém as operações(métodos) da classe   

O diagrama de classes permite aos analistas usarem uma notação de fácil compreensão
pelo cliente estimulando-os desta a forma a revelar detalhes importantes sobre o problema
que necessita ser resolvido.

Uma das principais vantagens do uso de objetos é que o objeto não precisa revelar todos os seus atributos e comportamentos.

Em um bom projeto OO (pelo menos o que é geralmente aceito como bom), um objeto só deve revelar as interfaces que outros objetos deve ter para interagir com ele. Os detalhes não pertinentes para a utilização do objeto deve estar oculto de todos os outros objetos.

O encapsulamento é definido pelo fato de que os objetos contêm tanto os atributos como os comportamentos. O ocultamento de dados é uma parte importante do encapsulamento.

Por exemplo, um objeto que calcula o quadrado de um número deve fornecer uma interface para obter o resultado. Contudo, os atributos internos e os algoritmos usados para calcular o quadrado não precisam ser disponibilizados para o objeto solicitante.

Classes robustas são projetadas com encapsulamento em mente.

A interface definida em cada classe define os meios fundamentais de comunicação entre objetos. Cada projeto de classe especifica as interfaces para a instanciação adequada e operação de objetos. Qualquer comportamento que o objeto fornece deve ser executado por uma mensagem enviada usando uma das interface fornecidas.

A interface deve descrever completamente como os usuários da classe interagem com a classe. Na maioria das linguagens OO, os métodos que fazem parte da interface são designados como Public.

Herança, a palavra mágica

Uma das características mais poderosas de programação OO é, talvez, a reutilização de código.

Se você esta pensando que um projeto estruturado também permite reusar código, tudo bem , ele permite, mas existe um limite para isso, e, quando você escreve um procedimento pode usá-lo quantas vezes quiser, mas o projeto OO vai um passo adiante; ele permite que que você defina relacionamentos entre as classes e isso facilita não somente a reutilização de código mas melhora todo o projeto, através da organização das classes.

A herança é principal meio de fornecer essa funcionalidade.

A herança permite que uma classe herde os atributos e métodos de outra classe, e isso permite a criação de novas classes pela abstração de atributos e comportamentos comuns.

  1. Herança é um conceito chave usado na programação orientada a objetos para descrever uma relação entre as classes;
  2. Por meio da herança uma classe copia ou herda todas as propriedades, atributos e métodos de uma outra classe, podendo assim estender sua funcionalidade;
  3. A classe que cede os membros para a outra classe é chamada superclasse, classe pai ou classe base;
  4. A classe que herda os membros da outra classe é chamada subclasse ou classe derivada;
  5. A herança permite a reutilização de código e especifica um relacionamento de especialização/generalização do tipo "é um";
  6. Embora seja recurso poderoso a herança deve ser usada somente quando necessário pois pode levar a um acoplamento forte entre as classes do seu projeto dificultando a sua reusabilidade e a manutenção;
  7. Existe a herança de implementação onde uma classe derivada herda da classe base e a herança de interface onde uma classe pode herda de uma interface, neste caso apenas as assinaturas dos métodos são herdados sendo que os métodos devem ser implementados;

Polimorfismo

Polimorfismo significa muitas formas , na orientação a objetos você pode enviar uma mesma mensagem para diferentes objetos e fazê-los responder da maneira correta. Você pode enviar a mensagem mover para cada objeto semelhante a um veiculo e cada um vai se comportar de maneira diferente para atender a sua solicitação.

 

Quando uma mesma mensagem pode ser processada de diferentes formas temos um exemplo de polimorfismo.

 

Usando polimorfismo podemos :

  1. Invocar métodos da classe derivada através da classe base em tempo de execução;
  2. Permitir que classes forneçam diferentes implementações de métodos que são chamados com o mesmo nome;

Implementação C# e VB .NET

A seguir temos uma implementação na linguagem C# e VB .NET da classe Pessoa e sua utilização em uma aplicação do tipo Console:

1- Linguagem C#

using System;
namespace Classes_objetos
{
    class Program
    {
        static void Main(string[] args)
        {
            Pessoa macoratti = new Pessoa();
            macoratti.Nome = "Macoratti";
            macoratti.Endereco = "Rua Projetada 100";
            Console.WriteLine(macoratti.getEnderecoCompleto());
            Console.ReadLine();
        }
    }
    public class Pessoa
    {
        public String Nome { get; set; }
        public String Endereco { get; set; }
        public string getEnderecoCompleto()
        {
            return Nome + "\n" +  Endereco;
        }
    }
}

2- Linguagem VB .NET

Module Module1
    Sub Main()
        Dim macoratti As New Pessoa()
        macoratti.Nome = "Macoratti"
        macoratti.Endereco = "Rua Projetada 100"
        Console.WriteLine(macoratti.getEnderecoCompleto())
        Console.ReadLine()
    End Sub
    Public Class Pessoa
        Public Property Nome() As [String]
        Public Property Endereco() As [String]
        Public Function getEnderecoCompleto() As String
            Return Nome + vbLf + Endereco
        End Function
    End Class
End Module

Após definir a classe Pessoa criamos um objeto do tipo Pessoa chamado macoratti usando a instrução New.

A seguir atribuímos valores para os atributos Nome e Endereco e usamos o método GeEnderecoCompleto() para exibir o nome e endereço do objeto criado.

Finalizando eu gostaria de deixar claro que haveria  muita coisa para cobrir quando se discute o paradigma orientado a objetos. No entanto, espero que você tenha tido uma boa compreensão dos seguintes tópicos:

  1. Encapsulamento - Encapsular os dados e os comportamentos em um único objeto é de primordial  importância no desenvolvimento OO. Um único objeto contém seus dados e comportamentos e pode esconder o que quer de outros objetos.
  2. Herança - Uma classe pode herdar de outra classe e aproveitar os atributos e métodos definidos pela superclasse.
  3. Polimorfismo - Polimorfismo significa que objetos semelhantes podem responder à uma mesma  mensagem de maneiras diferentes. Por exemplo, você pode ter um sistema com muitas formas.  No entanto, um círculo, um quadrado, e uma estrela de cada um são tirados de forma diferente. Usando polimorfismo, você pode enviar a cada uma dessas formas a mesma mensagem (por exemplo, desenhar) e cada forma é responsável por desenhar a si mesmo.
  4. Composição - Composição significa que um objeto é construído a partir de outros objetos.(Eu não falei diretamente sobre composição mas é um conceito intuitivo)

 Para saber mais sobre os conceitos do paradigma da orientação a objetos na linguagem VB .NET acompanhe o curso:

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

Assim também vós, meus irmãos, fostes mortos quanto à lei mediante o corpo de Cristo, para pertencerdes a outro, àquele que ressurgiu dentre os mortos a fim de que demos fruto para Deus.

Pois, quando estávamos na carne, as paixões dos pecados, suscitadas pela lei, operavam em nossos membros para darem fruto para a morte.

Mas agora fomos libertos da lei, havendo morrido para aquilo em que estávamos retidos, para servirmos em novidade de espírito, e não na velhice da letra.

Rom 7:4-6

 

Referências:


José Carlos Macoratti