Artigo no estilo: Curso

Por que eu devo ler este artigo:Neste artigo veremos os princípios SOLID da orientação a objetos que permitem que nossos softwares sejam flexíveis, de fácil manutenção e entendimento do código. Na primeira parte do artigo aprenderemos a aplicar os três dos cinco princípios SOLID (Responsabilidade Única, Aberto/Fechado, Substituição de Liskov com o Delphi em situações bem comuns do dia-a-dia de todo desenvolvedor.

Veremos as vantagens e as maneiras corretas de aplicar este princípio passo-a-passo. Ainda veremos como unir o desenvolvimento RAD do Delphi com boas práticas de orientação a objetos.

Muitos desenvolvedores Delphi não seguem bons princípios de orientação a objetos com a justificativa ou desculpa como eu prefiro dizer que a Linguagem/IDE/Compilador não oferece bons frameworks para trabalhar desta maneira.

Na verdade o que falta para esses desenvolvedores é abrir a mente para um pensamento orientado a objetos como fazem desenvolvedores Java e C#, pois o Delphi é uma linguagem multiparadigma, suporta tanto a programação procedural quanto a orientada a objetos, cabe a nós desenvolvedores escolhermos de que maneira preferimos trabalhar.

É claro que a adição de frameworks de mapeamento objeto-relacional ou injeção de dependências facilitaria a vida dos desenvolvedores e a Embarcadero poderia focar um pouco mais neste quesito.

É perfeitamente possível unir toda a produtividade que o Delphi nos oferece por ser uma ferramenta RAD com bons princípios de orientação a objetos e isto ficará muito claro no decorrer do artigo.

Alguns desenvolvedores acreditam que mesmo quando estamos somente adicionando e manipulando componentes em um formulário, estamos trabalhando orientado a objetos, pois cada novo formulário que criamos no Delphi gera uma nova classe que herda de TForm e ao adicionar componentes no formulário estamos adicionando objetos no formulário, pois cada componente representa uma classe que herda em última instância da classe TComponent.

SOLID

No desenvolvimento orientado a objetos existem alguns princípios que todo o bom desenvolvedor de sistemas deve adotar para ter um sistema com um código mais limpo e de fácil entendimento e manutenção, e quando exista a necessidade de manutenção ela seja rápida e concisa, de forma que não cause nenhum impacto em outros módulos, sendo mais evolutivas e flexíveis.

SOLID são cinco princípios básicos da orientação a objetos que trazem inúmeros benefícios em uma modelagem de classes. Estes princípios foram base para muitos dos padrões de projeto existentes nos dias de hoje. Cada letra representa um princípio, são eles:

· S – Single Responsibility Principle (SRP): princípio da responsabilidade única;

· O – Open Closed Principle (OCP): princípio do aberto/fechado;

· L – Liskov Substituition Principle (LSP): princípio da substituição de Liskov;

· I – Inteface Segregation Principle (ISP): princípio da segregação de interfaces;

· D – Dependency Inversion Principle (DIP): princípio da inversão de dependência;

Serão tratados cada um dos princípios de forma individual, os três primeiros nesta primeira parte do artigo e os dois últimos na segunda parte do artigo, na próxima edição da revista ClubeDelphi.

Quando seguimos estes princípios da orientação a objetos conseguimos ter uma modelagem de classes bastante correta, de forma que os sistemas não tenham que sofrer muitas alterações nas classes já existentes no futuro.

É indiscutível que os princípios SOLID são base para o desenvolvimento de qualquer aplicação que deseje seguir o paradigma orientado a objetos.

SRP (Sigle Responsibility Principle)

Este princípio de responsabilidade única da orientação a objetos nos ensina que nossas classes devem ter somente uma responsabilidade dentro do modelo e deve estar completamente encapsulada em seus métodos. Todos os métodos contidos nas classes, tanto os privados, protegidos ou públicos devem agir de modo a se completarem e atingir o objetivo que é único desta classe.

Quando seguimos este princípio da maneira descrita acima, esta classe terá somente uma razão para ser alterada. Esta classe poderá ainda conter vários métodos sendo que os mesmos contribuam para somente aquela única tarefa proposta para a classe, também não teremos muitas dependências de outros módulos, de maneira que ao alterarmos esta classe não será necessário recompilar outras classes do sistema.

Quando construímos classes que seguem o princípio de responsabilidade única podemos ter a certeza que estamos criando um sistema que tem um baixo acoplamento (BOX 1) entre os módulos.

BOX 1. Acoplamento

Alto acoplamento é nome dado à ocorrência de alto grau de dependência entre partes de um software, sendo que estas partes deveriam funcionar de forma independente. Numa situação real, do dia a dia poderíamos pensar da seguinte maneira: para se conectar a um banco de dados para realizar uma atividade possuímos um método que realiza a conexão com o banco.

No interior de seu método de conexão, existe a chamada para outro método, sendo que este último apenas identifica se ocorreu algum erro e registra em um arquivo ou tabela de logs do sistema.

Assim, sabemos que existe uma dependência explícita do método de conexão para com o método de registro de log. Um só pode funcionar se o outro funcionar. Tal dependência é chamada de acoplamento. Se este fato ocorre de forma sistemática no projeto de software, dizemos que a aplicação é altamente acoplada.

Este princípio nos ensina que nossas classes devem ter uma única tarefa em nossa aplicação, do contrário significa que ao certo devíamos dividir esta classe em duas ou mais classes para seguir o princípio, porque cada tarefa é uma fonte de mudanças no sistema e estas tarefas por isso devem estar bem isoladas de forma que uma tarefa não influa em outras.

É um princípio bastante simples e que devemos adotar para termos um sistema que demande facilidade de manutenção no futuro.

OCP – Open Closed Principle

Este princípio do Aberto/Fechado da orientação a objetos é um dos que mais chama a atenção dos estudiosos de arquitetura de sistemas, ele nos traz uma definição muito interessante que devemos tomar cuidado em nossas classes, no diz que elas devem estar abertas para extensão e fechadas para modificação, ou seja, quando criamos uma classe devemos levar em consideração uma codificação que muito dificilmente precise ser alterada no futuro, mas deve ter métodos que facilite sua extensão para a modificação de seu comportamento e sem que seja necessário a modificação da classe base.

O princípio do Aberto/Fechado é um grande aliado dos desenvolvedores, principalmente na hora da manutenção dos sistemas, pois se temos um sistema em pleno funcionamento, nada mais correto de bloquearmos a alteração das classes já existentes e que estão cumprindo corretamente suas tarefas, se precisamos da alteração de um comportamento destas classes podemos apenas estende-la com o mecanismo de herança por exemplo.

Outra grande vantagem da adoção deste princípio é que não serão mais necessários fazer testes unitários (BOX 2) novamente nas classes já existentes, somente na classe que está sendo adicionada naquele momento.

BOX 2. Testes Unitários

Os Testes Unitários são um assunto vital para o bom desenvolvimento de qualquer sistema. Eles consistem em testes em cada unidade do sistema (classes), de modo que as mesmas estejam funcionando da melhor maneira.

Estes testes unitários são bastante presente nas principais linguagens orientadas a objetos, porém quem programa em Delphi não costuma fazer estes testes, pois trabalham somente de forma procedural e não conseguem tirar proveito deste excelente princípio que previne a ocorrência de erros nas classes e tornam o código muito mais confiável.

LSP - Liskov Substituition Principle

O princípio da Substituição de Liskov leva este nome pois o seu conceito foi introduzido por Bárbara Liskov e Jeannette Wing em 1993 através do artigo Family Values: A Behavioral Notion of Subtyping.

Este princípio nos ensina que um objeto de uma classe qualquer deve permitir a substituição em um sistema por qualquer instância de suas classes filhas e classes derivadas também devem possibilitar a substituição por sua classe base.

Este princípio é vital para a boa aplicação da orientação a objetos, pois ele facilita e muito o uso do polimorfismo (BOX 3), pois desta forma todo e qualquer método pode ser utilizado tanto na classe base quanto em todas as especializações dela sem nenhum problema.

BOX 3. Polimorfismo

Em Orientação a Objetos o Polimorfismo permite que usemos referências de tipos de classes mais abstratas para representar o comportamento das classes concretas que referenciam. Assim é possível tratar várias classe de maneira homogênea através da interface da classe mais abstrata.

Se temos uma classe filha que não implementa todos os métodos da classe pai então há de se considerar que talvez estejamos fazendo um mal uso do mecanismo de herança em nossa modelagem de classes e que esta herança na realidade nem deveria existir.

Devemos ter muito cuidado com o uso da herança em nossos sistemas, pois a herança muitas vezes acaba quebrado o encapsulamento de nossas classes ou expondo para as classes derivadas métodos e propriedades que nem fazem sentido para ela.

SRP (Sigle Responsibility Principle) na prática

Existem vários exemplos de implementação deste princípio na web, porém na sua grande maioria trazem abordagens muito abstratas sobre o assunto, que foge do dia a dia do desenvolvedor. Nós, porém iremos trazer um exemplo de aplicativo comum a todos os programadores Delphi, que é o uso de um cadastro de clientes, com persistência e log de erros.

Consideramos uma aplicação VCL Win32, com um cadastro de clientes simples, onde temos um formulário com botões para criarmos um novo cliente e outro para persistir este cliente na base de dados, neste caso um arquivo XML simples vinculado a um ClientDatSet, além do componente ApplicationEvents que nos proporciona a codificação de alguns eventos importantes da aplicação. Veja a interface com os componentes visuais e não visuais na Figura 1.

Na Listagem 1 a interface da classe do formulário, juntamente com a implementação dos eventos dos botões e do evento OnException do componente ApplicationEvents.

Figura 1. Interface do Cadastro de Clientes

Listagem 1. Interface e Implementação do código do formulário de clientes


  01 procedure TfrmCliente.ApplicationEventsException
     (Sender: TObject; E: Exception);
  02 const ARQ_ERRO = 'C:\LogErros.txt';
  03 var Arquivo: TextFile;
  04 begin
  05   AssignFile(Arquivo, ARQ_ERRO);
  06   try
  07     if FileExists(ARQ_ERRO) then
  08       Append(Arquivo)
  09     else Rewrite(Arquivo);
  10     Writeln(Arquivo, E.Message);
  11   finally
  12     CloseFile(Arquivo);
  13   end;
  14 end;
  15 
  16 procedure TfrmCliente.btnNovoClick(Sender: TObject);
  17 begin
  18   cdsCliente.Append;
  19 end;
  20 
  21 procedure TfrmCliente.btnSalvarClick(Sender: TObject);
  22 begin
  23   cdsCliente.Post;
  24 end;

Vamos pensar neste formulário e código de acordo com o princípio de responsabilidade única, vemos que são muitas as responsabilidades pr ...

Quer ler esse conteúdo completo? Tenha acesso completo