Olá pessoal
Neste post vamos conhecer alguns conceitos de programação orientada a objetos (POO) que nos ajudam a pensar em como estruturar projetos orientados a objetos. Ambos os conceitos abordados neste post estão descritos no livro “Utilizando UML e Padrões – Uma introdução à Análise e ao Projeto Orientado a Objetos e ao Desenvolvimento Iterativo” de Craig Larman – Livro muito bom que trata em detalhes de diversos assuntos bastante pertinentes no nosso dia-a-dia: processos de desenvolvimento iterativos, incrementais e ágeis, papéis e responsabilidades, artefatos, UML, conceitos de programação orientada a objetos, RDD, padrões GRASP, design-patterns (GOF) e outros.
Vamos começar então pelo RDD. Segundo o livro, RDD é uma metáfora geral que nos leva a raciocinar sobre projetos de software orientados a objetos, sob o ponto de vista de responsabilidades. Por responsabilidades, entende-se o que nossas classes de objetos ou mesmo componentes de software devem fazer e saber. Em um modelo de classes o fazer é realizado por métodos e o saber por atributos. Outro conceito envolvido no RDD é o de colaboração. Uma vez definidas as responsabilidades, há de se definir como seus objetos colaboração para que o objetivo seja atingido.
Já o GRASP define nove padrões ou princípios voltados à atribuição de responsabilidades, que apoiam o RDD. Analisando estes conceitos e os padrões GRASP, que veremos em detalhe mais a frente, podemos concluir que ambos apenas endereçam questões básicas de orientação a objetos. E o objetivo é justamente esse. Tanto RDD quanto GRASP servem como uma ferramenta para apoiar no domínio de conceitos básicos de programação orientada a objetos. E quando falamos de conceitos básicos, logo veremos que diversos tópicos abordados fundamentam outros padrões mais específicos, como por exemplo, MVC e os design-patterns do GOF. Isso é interessante, porque para entender estes padrões mais específicos temos que ter os conceitos básicos bem fundamentados. Outro ponto importante é que alguns padrões não se restringe apenas ao mundo de orientação a objetos. Alguns conceitos empregados nos padrões High Coesion, High Coupling, Indirection e Protected Variation são altamente pertinentes e recorrentes em arquiitetura de software. Vamos então aos padrões GRASP.
Creator – Este padrão determina quem é responsável por criar quem. Uma das possibilidades a considerar, por exemplo, é que uma classe A deve ser responsável por criar uma classe B caso a classe A tenha uma relação de composição com a classe B. Outra possibilidade citada por este padrão é que a classe A pode ser responsável por criar a classe B caso ela tenha consigo informações suficientes para a inicialização da classe B ou caso use B de maneira muito próxima. Considere, por exemplo, uma relação entre uma classe NotaFiscal e Item, que usualmente denota uma relação de composição. Ou seja, uma nota fiscal é composta por itens de forma que não faça sentido sua existência sem eles. Neste exemplo, a responsabilidade por criar instâncias da classe Item seria da classe NotaFiscal, que poderia fazê-lo através de uma operação “IncluirItem”.
Information Expert – Determina a qual classe deve ser atribuída a responsabilidade de prover uma nova funcionalidade. O padrão diz que a classe que possuir mais informações a respeito da funcionalidade em questão deve ser a responsável por provê-la. Considerando o exemplo anterior (NotaFiscal – Item), caso precisássemos saber a quantidade de itens de uma nota ou o valor total do itens quem deveria ser a classe responsável? A classe NotaFiscal é a classe que tem mais informações sobre seus Itens, já que ela é composta por Itens, logo, as operações ObterQuantidaDeItens e ObterValorTotal é uma responsabilidade da classe NotaFiscal. Note que tanto este quanto o padrão Creator são bem básicos e definem conceitos bastante triviais. O que é importante observar é que ambos definem regras gerais que estão por traz do que fazemos por “intuição” no dia-a-dia.
High Coesion – A alta coesão diz respeito à criação de classes que tratem de assuntos focados e bem definidos. Uma classe não coesa é aquela que trata de diversos assuntos distintos, tornando-se difícil de entender, manter, testar, evoluir e reutilizar. A alta coesão também suporta o baixo acoplamento (veja Low Coupling).
Low Coupling – O baixo acoplamento diz respeito à redução de dependência entre classes de forma que uma necessidade de mudança tenha menor impacto nos objetos dependentes. Projetar para baixo acoplamento envolve a utilização de conceitos de alta coesão (veja High Coesion), pois, classes mais coesas são menos dependentes entre si. Imagine, por exemplo, uma classe que contenha implementações de diversos assuntos diferentes – não coesa. Todos os demais módulos do sistema que dependam dos assuntos contidos nesta classe dependerão de uma mesma classe, de forma que alterações em qualquer um dos assuntos abordados proporcionem maior risco para todos os demais. Projetar para baixo acoplamento também envolve utilização de conceitos de encapsulamento. Encapsular significa esconder do mundo externo particularidades, implementações e informações que não digam respeito diretamente ao negócio / domínio, ou que sejam sujeitas a mudanças. Uma vez que tais informações sejam escondidas atrás de propriedades ou operações, por exemplo, as demais classes não serão afetadas quando houver alterações – ou seja, terão baixo acoplamento. O baixo acoplamento também pode ser atingido através de técnicas utilizadas para indireção (veja Indirection) e variação protegida (veja Protected Variation).
Por enquanto é só. No próximo artigo devo trazer os demais padrões GRASP: Controller, Pure Fabrication, Polymorphism, Indirection e Protected Variation. Até lá.