Delphi orientado à objetos – parte 1
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.
Comment