Delphi orientado à objetos – parte 1

Jul 27
2010

Já tem um bom tempo que programo com Delphi. E sempre ouvi críticas pesadíssimas sobre o quanto a linguagem é ruim. Eu sempre acreditei que existiram sempre programadores ruins e que os programas saiam ruins, o que gerou essa impressão negativa, bem como os vários problemas que a Borland (fabricante do Delphi, agora CodeGear) impôs nas mudanças de versão. Assim, resolvi desmistificar essa coisa de que é impossível programar orientado à objetos usando o Delphi.

Segue o material do nosso último treinamento, sobre como usar o Delphi, orientado à objetos.
Embora pareça que estamos trabalhando com OO desde sempre, afinal instanciamos objetos baseados em classes, isso não é inteiramente verdade.
Como me disse um professor certa vez: “Seu sistema é orientado à objetos? Ótimo. Me mostre a sua classe NotaFiscalSaída.”

Assim achei por bem usar um exemplo bem simples, estados e cidades para mostrar o poder que o Delphi tem e de quebra demonstrar que o que está errada é a maneira como programamos e não a linguagem que usamos, seja ela qual for.

Primeiramente, começamos com alguns paralelos. No Delphi, para criarmos uma classe, precisamos cria-la como um componente, para mais tarde, criar instancias dele. Usando o Delphi 2006, eu vou em File > New > Package. Então no Project Manager eu clico sobre o pacote com o botão direito e escolho Add New > Other…

A janela que se abrirá me dá várias opções, a que vamos usar está em Delphi Projects > Delphi Files > Component. No Wizard seguinte escolhemos de qual componente o nosso irá herdar suas características (não vou explicar herança aqui). Nesse momento escolheremos TComponent, para pegar somente o mínimo necessário. Na próxima tela, escolha o nome do componente em Class Name, para nós será TCidade (o “T” é padrão do Delphi, use sem questionar). Escolha a Pallete Page que deseja ou digite uma nova, lembre que esse campo é Case Sensitive, portanto atenção ao digitar. Preencha os demais campos se precisar.

A classe cidade:

unit cidade;

interface

uses
  SysUtils, Classes, Estado;

type
  TCidade = class(TComponent)
  private
    Fcid_nome: string;
    Fcid_codigo: integer;
    Festado: TEstado;
    procedure Setcid_codigo(const Value: integer);
    procedure Setcid_nome(const Value: string);
    procedure Setestado(const Value: TEstado);
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property cid_codigo: integer read Fcid_codigo write Setcid_codigo;
    property cid_nome: string read Fcid_nome write Setcid_nome;
    property estado: TEstado read Festado write Setestado;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Objetos Produtec', [TCidade]);
end;

{ TCidade }

procedure TCidade.Setcid_codigo(const Value: integer);
begin
  Fcid_codigo := Value;
end;

procedure TCidade.Setcid_nome(const Value: string);
begin
  Fcid_nome := Value;
end;

procedure TCidade.Setestado(const Value: TEstado);
begin
  Festado := Value;
end;

end.

Vamos falar um pouco da classe cidade. Nela eu coloquei os principais atributos de uma cidade, somente para exemplo. Percebam que os mesmos foram criados baseado na seguinte estrutura:

private
    Fcid_nome: string;
published
    property cid_nome: string read Fcid_nome write Setcid_nome;

(…)

procedure TCidade.Setcid_nome(const Value: string);
begin
  Fcid_nome := Value;
end;

Traduzindo, teremos uma propriedade com o nome cid_nome, do tipo string (notem que sem tamanho definido) que lê o valor para uma variável Fcid_nome e grava através de uma procedure chamada como Setcid_nome. Ótimo, mas o que ganhamos com isso? Para que esconder o real valor de uma variável ao invés de simplesmente torná-la pública? E para que criar um procedimento para atribuir o valor, se a mudança da visibilidade já resolveria? Parece tudo uma grande perda de tempo, mas é um foco na segurança e no reuso.
Imaginem que em determinado momento, nós precisaremos delimitar o tamanho da cidade para o máximo de caracteres que existem no banco de dados, que para o nosso exemplo é de 60 caracteres. Alterando o procedimento SetCid_Nome todo, eu disse TODO, o sistema passa a respeitar a nova regra, sem precisar avisar a nenhuma outra parte do sistema que isso aconteceu. Vejam como ficaria:

procedure TCidade.Setcid_nome(const Value: string);
begin
   if Length(Value) < 60 then
      Fcid_nome := Value;
end;

Viram que simples? Poderíamos melhorar ainda, criando uma mensagem de erro (exceção) que poderia ser tratada pela tela que realizou a chamada ou simplesmente exibida diretamente em tela. Algo mais ou menos assim:

procedure TCidade.Setcid_nome(const Value: string);
begin
   if Length(Value) < 60 then
      Fcid_nome := Value
   else
      raise Exception.Create('O nome da cidade não pode conter mais do que 60 caracteres.');
end;

Várias validações ou procedimentos poderiam ser feitos no momento em que a propriedade é atribuída, como preencher uma outra propriedade, carregar outros componentes em tela, enfim, o limite fica por conta da necessidade do programador.
Se eu não disse antes, o nome desse método chama-se encapsulamento, pois os atributos ficam protegidos (encapsulados) em métodos que lêem e escrevem nas variáveis.
Isso é meio caminho para um estereótipo usado em UML chamado JavaBean, que os meninos que mexem com Java devem conhecer bem.

Leave a Reply

Arquivo

Categorias