Programação orientada a objetos → No começo era...

O internauta vai encontrar milhares de materiais falando isso e aquilo sobre objetos.
Vão enaltecer esse tipo de programação como se fosse a solução pra todos os problemas programacionais.
A realidade é que a maioria deles não passam de asneiras.

A única coisa que se pode dizer é que houve uma evolução pra melhor.
Mas evoluiu do quê?
Do que a programação orientada a objetos evoluiu?
Poracaso os objetos evoluiram dalgum protoplasma? Os objetos poracaso evoluiram dos macacos siberianos?

EBER vai dizer do que os objetos evoluíram.
E Ele diz os objetos evoluíram simplesmente dos registros.
Sim, registros.


Um registro tem o seguinte formato→

Registro em Pascal
 
type
  TRegistro= record
    Campo0: TipoX;
    Campo1: TipoY;
    ...
    CampoN: TipoZ;
  end;

Já no início da programação esse tipo de encapsulamento de dados significava uma grande mão-na-roda pros programadores.
O sujeito consegue tratar um conjunto de dados como se fosse um dado só.
É o mesmo que pensar nas peças de Lego.
Cada Campo do registro é uma peça de Lego.
Um conjunto delas pregadas entre si pode formar um carrinho ou um animal qualquer.
Um exemplo mais prático. Uma carteira de CPF tem pelo menos os seguintes dados→

CPF
 
type
  TCPF= record
    NomeCompleto   : String;
    DataNascimento : String;
    NumeroInscricao: String;
  end;

O registro acima é um exemplo de objeto.
Se é um objeto então os programadores já programavam orientado a objetos muito antes do grande advento da dita programação orientada a objetos.

O que fizeram de novo foi uma evolução do encapsulamento de dados chamado registro.
As linguagens de programação forneceram uma maior flexibilidade a esse encapsulamento.
E qual foi essa flexibilidade?
Foram pézinhos com rodas?
Foram asinhas nas costas?
Foram diminutas turbinas de foguetes?
Essa flexibilidade poracaso foi o poder da invisibilidade?

Não.
Foram apenas usar os registros somente quando alocados em tempo de execução, compor novos registros a partir de outros já existentes (hereditariedade), a possibilidade de se incluir rotinas, o escopo dos elementos do registro e a redefinição de métodos (sobrecarga).
Nada mais que isso.


Esses registros evoluídos passaram a se chamar classes. E as variáveis das classes, a serem alocadas em tempo de execução, passaram a se chamar objetos.
Ou seja→

CPF
 
// Classe
type
  TCPF= class
    NomeCompleto   : String;
    DataNascimento : String;
    NumeroInscricao: String;
  end;

// Objeto da classe TCPF
var
  CPF: TCPF;

No exemplo acima a variável CPF só poderá ser usada quando for alocada em memória. Ou seja, quando se criar o objeto CPF.
A sintaxe pra criar um objeto é→

Criando o objeto CPF
 
  CPF:= TCPF.Create;

Até aí não houve grandes mudanças.
O que deixou a orientação a objetos mais atraente foi a capacidade de hereditariedade.

Hereditariedade
 
type
  // Classe base
  TCPF= class
    NomeCompleto   : String;
    DataNascimento : String;
    NumeroInscricao: String;
  end;

  // Classe derivada
  TCPFAtual= class (TCPF)
    DataEmissao: String;
  end;

Acima TCPFAtual herda todos os campos de TCPF.
Ou seja, teria o mesmo efeito de→

CPF atual
 
type
  TCPFAtual= class
    NomeCompleto   : String;
    DataNascimento : String;
    NumeroInscricao: String;
    DataEmissao    : String;
  end;

Depois vem a possibilidade de se inserir rotinas.
Nova nomenclatura→ os campos variáveis passaram a se chamar atributos e as rotinas são chamadas de métodos.

Os CPFs costumam aparecer formatados.
Os noves primeiros dígitos são separados por ponto em grupos de três. Os dois últimos dígitos são separados do restante porum hífen.
O próprio objeto então poderia possibilitar essa formatação já que o dado a ser utilizado é NumeroInscricao.
A rotina inserida no registro evoluído é Formatar.

Atributos e métodos
 
interface

type
  TCPF= class
    NomeCompleto   : String; // Atributo
    DataNascimento : String; // Atributo
    NumeroInscricao: String; // Atributo

    function Formatar: String; // Método
  end;

implementation

// Ex.: pra '00000000191' seria retornado '000.000.001-91' 
function TCPF.Formatar: String;

begin
  if Length (NumeroInscricao) = 11 then
    Result:= Copy (NumeroInscricao, 01, 3) + '.' +
             Copy (NumeroInscricao, 04, 3) + '.' +
             Copy (NumeroInscricao, 07, 3) + '-' +
             Copy (NumeroInscricao, 10, 2)
  else
    Result:= '';
end;

O escopo de atributos e métodos define o nível de acesso a eles.
Por exemplo, todos os atributos poderiam ficar inacessíveis ao usuário do objeto CPF.
O usuário teria acesso somente aos métodos.
E como se faz isso?
Tudo depende da linguagem de programação e do compilador usados.
Em Delphi usam-se as palavras reservadas protected e public.
A primeira esconde os atributos e métodos entre o módulo que implementa o objeto e o módulo que acessa o objeto. A segunda os deixa acessíveis a todos os módulos.
Ou seja→

Escopo de atributos e métodos
 
type
  TCPF= class
    protected // Acesso restrito
      NomeCompleto   : String;
      DataNascimento : String;
      NumeroInscricao: String;
    public // Acesso público
      function Formatar: String;
  end;

A redefinição de métodos é feita durante o processo de herança.
No exemplo acima os atributos estão fechados pro mundo externo ao módulo que implementa a classe TCPF.
Portanto é necessário um mecanismo pra atribuir e obter o conteúdo desses atributos.

Abaixo, Create faria a inicialização dos atributos e ObterAtributo a obtenção de seus conteúdos.

A palavra reservada virtual informa ao compilador que o método poderá ser redefinido (sobrecarregado) pelas classes filhos e override informa que o método em questão está sendo redefinido (em relação à classe pai).
Na situação abaixo TCPF é a classe pai e TCPFAtual é a classe filho.

Sobrecarga de métodos
 
type
  TCPF= class
    protected
      NomeCompleto   : String;
      NumeroInscricao: String;
      DataNascimento : String;
    public
      constructor Create (ANumeroInscricao, ANomeCompleto, ADataNascimento: String);
      function ObterAtributo (AAtributo: Integer): String; virtual;
  end;

  TCPFAtual= class (TCPF)
    protected
      DataEmissao: String;
    public
      constructor Create (ANumeroInscricao, ANomeCompleto, ADataNascimento, ADataEmissao: String); 
      function ObterAtributo (AAtributo: Integer): String; override;
  end;




Um exemplo em Delphi

Há 3 módulos→ CPF.dpr, Principal.pas e ClasseCPF.
O primeiro é o ponto de entrada do programa pelo sistema operacional. O segundo é o módulo que usará os objetos TCPF e TCPFAtual. O terceiro é o módulo que implementa as classes desses objetos.

CPF.dpr
program CPF;

uses Forms, Principal in 'Principal.pas' {FormPrincipal}, ClasseCPF in 'ClasseCPF.pas';

begin
  Application.Initialize;
  Application.CreateForm (TFormPrincipal, FormPrincipal);
  Application.Run;
end.


Principal.pas
unit Principal;

interface

uses Windows, Forms;

type
  TFormPrincipal= class (TForm)
    procedure FormCreate (Sender: TObject);
  end;

var
  FormPrincipal: TFormPrincipal;

implementation

uses ClasseCPF;

{$R *.dfm}
procedure TFormPrincipal.FormCreate (Sender: TObject);
var
  CPF     : TCPF;
  CPFAtual: TCPFAtual;

begin
  CPF                  := TCPF.Create ('00000000191', 'Nosferatus da Silva', '6/6/6');
  CPFAtual             := TCPFAtual.Create ('00000000191', 'Nosferatus da Silva', '6/6/6', '9/9/9');
  FormPrincipal.Caption:= CPF.Formatar + ' ' + CPF.ObterAtributo (1) + ' ' + CPFAtual.ObterAtributo (3);
  CPF.Free;
  CPFAtual.Free;
end;
end.


ClasseCPF.pas
unit ClasseCPF;

interface

type
  TCPF= class
    protected
      NomeCompleto   : String;
      NumeroInscricao: String;
      DataNascimento : String;
    public
      constructor Create (ANumeroInscricao, ANomeCompleto, ADataNascimento: String);
      function ObterAtributo (AAtributo: Integer): String; virtual;
      function Formatar: String;
  end;

  TCPFAtual= class (TCPF)
    protected
      DataEmissao: String;
    public
      constructor Create (ANumeroInscricao, ANomeCompleto, ADataNascimento, ADataEmissao: String); 
      function ObterAtributo (AAtributo: Integer): String; override;
  end;

implementation
constructor TCPF.Create (ANumeroInscricao, ANomeCompleto, ADataNascimento: String);

begin
  NomeCompleto   := ANomeCompleto;
  NumeroInscricao:= ANumeroInscricao;
  DataNascimento := ADataNascimento;
end;
function TCPF.ObterAtributo (AAtributo: Integer): String; 

begin
  case AAtributo of
    0: Result:= NumeroInscricao;
    1: Result:= NomeCompleto;
    2: Result:= DataNascimento;
  else
    Result:= '';
  end;
end;
// Ex.: pra '00000000191' seria retornado '000.000.001-91'
function TCPF.Formatar: String;

begin
  if Length (NumeroInscricao) = 11 then
    Result:= Copy (NumeroInscricao, 01, 3) + '.' +
             Copy (NumeroInscricao, 04, 3) + '.' +
             Copy (NumeroInscricao, 07, 3) + '-' +
             Copy (NumeroInscricao, 10, 2)
  else
    Result:= '';
end;



constructor TCPFAtual.Create (ANumeroInscricao, ANomeCompleto, ADataNascimento, ADataEmissao: String);

begin
  inherited Create (ANomeCompleto, ANumeroInscricao, ADataNascimento);
  DataEmissao:= ADataEmissao;
end;
function TCPFAtual.ObterAtributo (AAtributo: Integer): String; 

begin
  if AAtributo = 3 then
    Result:= DataEmissao
  else
    Result:= ObterAtributo (AAtributo);
end;
end.



Clique aqui pra baixar o código (4,81 Ko)





http://transeberiano.brinkster.net