Um dos aspectos mais valorizados num código é ele não ter trechos repetidos sem necessidade, se há código repetido, provavelmente pode ser refatorado. Refatorar significa manter a funcionalidade quebrando um trecho grande de código em pedaços menores, onde os pedaços menores poderão ser reutilizados por serem transformados em procedimentos ou funções e no caso do pascal, um subprocedimento.
Imagine um botão cujo código seja:
var
ACaption:String;
ATitle:String;
AText:String;
AButtonText1:String;
AButtonText2:String;
AResult:TModalResult;
begin
AResult:=mrNone;
ACaption:='Ser ou não ser';
ATitle:='Eis a questão:';
AButtonText1:='Sim';
AButtonText2:='Não';
AText:='Escolha sim ou não';
with TTaskDialog.Create(self) do
try
Caption := ACaption;
Title := ATitle;
Text := AText;
CommonButtons := [];
with TTaskDialogButtonItem(Buttons.Add) do
begin
Caption := AButtonText1;
ModalResult := mrYes;
end;
with TTaskDialogButtonItem(Buttons.Add) do
begin
Caption := AButtonText2;
ModalResult := mrNo;
end;
MainIcon := tdiQuestion;
if Execute then
begin
AResult:=ModalResult;
end;
finally
Free;
end;
O Objetivo do código é simplesmente mostrar uma mensagem ao usuário:
Refatorando para um método ou função
Daí você decide criar um segundo botão com uma funcionalidade diferente, porém reutilizará uma mensagem de confirmação similar ao utilizado no primeiro botão, e decide dar um Ctrl+C/Ctrl+V e apenas modifica as variáveis que representam o texto a ser exibido:
var
ACaption:String;
ATitle:String;
AText:String;
AButtonText1:String;
AButtonText2:String;
AResult:TModalResult;
begin
AResult:=mrNone;
ACaption:='Tem certeza?';
ATitle:='Vai apagar tudo?';
AButtonText1:='Sim';
AButtonText2:='Não';
AText:='Isso eliminará todos os dados!';
with TTaskDialog.Create(self) do
try
Caption := ACaption;
Title := ATitle;
Text := AText;
CommonButtons := [];
with TTaskDialogButtonItem(Buttons.Add) do
begin
Caption := AButtonText1;
ModalResult := mrYes;
end;
with TTaskDialogButtonItem(Buttons.Add) do
begin
Caption := AButtonText2;
ModalResult := mrNo;
end;
MainIcon := tdiQuestion;
if Execute then
begin
AResult:=ModalResult;
end;
finally
Free;
end;
(...)
Provavelmente vocẽ fez isso porque está com pressa, e verdadeiramente é isso que acontece com prazos apertados. Mas depois de um exaustivo trabalho, você concluiu as funcionalidades do programa e agora vem a parte chamada de “melhorias”, onde removeremos comentários desnecessários e …. refatoração. Para refatorar observamos em nosso código, as repetições e daí percebemos que isso aqui:
with TTaskDialog.Create(self) do
try
Caption := ACaption;
Title := ATitle;
Text := AText;
CommonButtons := [];
with TTaskDialogButtonItem(Buttons.Add) do
begin
Caption := AButtonText1;
ModalResult := mrYes;
end;
with TTaskDialogButtonItem(Buttons.Add) do
begin
Caption := AButtonText2;
ModalResult := mrNo;
end;
MainIcon := tdiQuestion;
if Execute then
begin
AResult:=ModalResult;
end;
finally
Free;
end;
Esta sendo repetido nos dois botões. Daí você sabe e tem noção que é possivel criar uma função com ela e trocar o trecho acima por uma função. Claro que dependendo de sua experiência isso será fácil fazer, mas porque não usar a IDE do Lazarus para isso. Faça assim:
1. Marque o trecho repetido:
2. Vá em Source|Refactoring|Extract Procedure…
3. Selecione o que a extração deverá fazer, geralmente transformando-a método privado quando o trecho será reutilizado no próprio form ou publico quando o mesmo será reutilizado em unidades/formulários diferentes. Há um checkbox quando a IDE detecta que pode ser transformando em uma função, neste caso você pode determinar o tipo de retorno e o nome do método(name of new procedure):
E ao clicar extract….O sistema então criará um código:
4. A ordem importa?
Em nosso exemplo foi criado o método:
PerguntarDlg( AButtonText2, AButtonText1, AText, ATitle, ACaption);
Mas note que a ordem dos parâmetros não foi decidida por mim, assim, caso não goste vá até o método gerado e acerte a ordem do jeito que planeja usá-los, eu inclusive coloco minhas personalizações:
Quando você modifica a assinatura do método, use Ctrl+Shift+C para que a IDE faça o ajuste também na declaração.
Agora você tem um método que pode ser usado em dois OnClicks de botões sem duplicações de linhas, apenas modificando os parâmetros usado no método PerguntarDlg.
Refatorar para subprocedimento(sub procedure)
Veja o que há de errado neste código:
Há trecho de código repetido, nele o programador se preocupou em destruir um objeto chamado “q1” quando o usuário desistisse de executar uma query, mas aí houve repetição do mesmo código, será que há como refatorar já que se trata de objetos locais?
- Sim, novamente vamos marcar apenas as linhas repetidas:
2. Selecionamos Source|Refactoring|Extract Procedure…
3. Selecione o que a extração deverá fazer, mas dessa vez marcaremos a opção Sub Procedure e daremos um nome adequado de LiberarMemoria já que o objetivo do trecho de código é destruir objetos:
4. Note agora como ficou o código:
Um procedimento LiberarMemoria tornou-se um subprocedimento para que possamos reutilizá-lo em todos os trechos que antes tinham:
q1.close;
q1.free;
Assim nosso código tornou-se menor, mais eficiente e muito melhor de entender.
Conclusion
É sempre preferível começar um projeto tomando a iniciativa em refatorá-lo desde o inicio, mas sabemos como às vezes é necessário correr contra o tempo para entregar as coisas dentro do prazo e deixamos de tomar essa iniciativa desde o principio. No final do projeto é bom saber que podemos usar a IDE do Lazarus para nos ajudar a refatorar nossas repetições de código.