INTRODUÇÃO

Como desenvolvedores, nós enfrentamos vários problemas para lidar com a informação nos sistemas: estruturar e armazenar as informações, transformar dados para que possam ser lidos pelos usuário, agrupar dados de diferentes sistemas etc. Assim, desenhar um sistema e sua arquitetura nem sempre é uma tarefa simples e direta. Além disso, conforme aprendemos mais sobre o domínio e a maneira como o sistema é utilizado, percebemos que o desenho inicial não será suficiente e sentimos a necessidade de modificá-lo.

No entanto, a maioria dos desafios que encontramos não é único. Certamente o domínio do sistema pode ser diferente, mas a essência dos problemas continua a mesma: como lidar com informação. Assim surgiu a ideia dos Padrões de Projeto, como uma base coletiva de conhecimento com soluções para esses “problemas comuns” que encontramos todos os dias.

Ao longo deste livro vamos ver como se deu o surgimento dos Padrões de Projeto e como eles foram adaptados para o desenvolvimento de software. Em seguida vamos analisar características do paradigma Orientado a Objetos e como eles buscam simplificar o desenvolvimento de aplicações. Por fim, serão explorados dois exemplos de padrões voltados para o desenvolvimento Orientado a Objetos, para exemplificar como eles podem ajudar na manutenção de sistemas.

O QUE É UM PADRÃO DE PROJETO?

Desenvolvimento de software é uma área relativamente nova comparada com outras áreas de conhecimento. Contando a partir da Ada Lovelace como a desenvolvedora do primeiro programa de computador e o surgimento da Máquina de Turing, ainda não temos 100 anos de história.

Por isso, muitas das nossas práticas são “emprestadas” de outras áreas. O maior exemplo é a Engenharia de Software onde tentamos aplicar muitas das ideias de outras Engenharia nos projetos de desenvolvimento de software.

O Surgimento dos Padrões de Projeto

O surgimento dos Padrões de Projeto, por exemplo, vem da arquitetura, através do livro “A Patter Language” escrito por Christopher Alexander, Sara Ishikawa e Murray Silverstein, do Center for Environmental Structure of Berkeley, California, publicado em 1977.

O livro define uma linguagem chamada pelos autores de “linguagem de padrões”, que se origina a partir dos 253 padrões apresentados no livro. O objetivo é que, com essa linguagem em comum, pessoas ao redor do mundo possam compartilhar ideias sobre como organizar bairros, cidades, projetar casas, escritórios e quaisquer outros espaços.

Quando levamos esse conceito para o mundo do desenvolvimento, temos os Padrões de Projeto como soluções de implementação para um problema em um determinado contexto. O objetivo ao documentar as soluções comumente encontradas é montar um “banco de conhecimento” onde pessoas com o mesmo problema podem consultar qual seria uma boa solução.

Com o ritmo que cresce a tecnologia da informação, essa base de conhecimento se torna ainda mais valiosa pois nos permite aprender com as experiências de outras pessoas. Mas, antes de explorar os padrões em si, é importante entender como essa base de conhecimento surgiu.

O livro “Padrões de Projeto - Soluções Reutilizáveis de Software Orientado a Objetos” da famosa Gangue dos Quatro (Gang of Four em inglês) é talvez a referência mais utilizada sobre o assunto. Esse livro popularizou os conceitos de Padrões de Projeto apresentando as soluções em C++ e Smalltalk, duas linguagens com características bem diferentes e que faziam sucesso nos anos 90.

Um ponto importante sobre padrões é que eles não são “inventados”, mas sim extraídos de códigos reais. A solução proposta por um padrão surge do conhecimento comum de várias pessoas que passaram pelo mesmo problema e aplicaram soluções semelhantes. A maior prova disso é que os livros que documentam Padrões de Projeto são geralmente escritos por várias pessoas.

Outro bom exemplo é o livro “Padrões de Arquitetura de Aplicações Corporativas” escrito por Martin Fowler com a colaboração de David Rice, Mathew Foemmel, Edward Hieatt, Robert Mee e Randy Stafford. A diferença deste livro é que os padrões apresentados não são específicos para linguagens Orientada a Objetos, mas para projetos corporativos, que precisam ser mais robustos e lidar com problemas não triviais.

Existe também Padrões de Projeto que propões soluções para problemas específicos de uma linguagem ou plataforma, como por exemplo o livro “Core J2EE Patterns”, que apresenta soluções específica para a linguagem Java na plataforma Java 2 Enterprise Edition. Eles continuam sendo considerados padrões, a única diferença é que o contexto de sua aplicação é mais restrito.

Os padrões da Gangue dos Quatro

Sendo a referência mais conhecida, é bem provável que ao ouvir falar de padrões de projeto você escute sobre um dos 23 padrões documentados pela Gangue do Quatro. Para linguagens Orientadas a Objetos esses padrões são tão úteis que são encontrados em muitas das bibliotecas mais utilizadas, e alguns são aplicados até mesmo na biblioteca padrão da linguagem.

Ao longo do livro os autores constroem uma aplicação para exemplificar as várias situações de onde os Padrões de Projeto foram extraídos. Cada um deles é documentando com: nome, objetivo, motivação, contexto, solução e o exemplo. Além disso os padrões são classificados de acordo com a natureza do problema que tenta resolver: criar objetos (padrões de criação), estruturar os objetos (padrões estruturais) ou dividir comportamento (padrões comportamentais).

Padrões de Criação

Factory Method, Abstract Factory, Builder, Prototype e Singleton

Os Padrões de Criação tem como intenção principal abstrair o processo de criação de objetos, ou seja, a sua instanciação. Desta maneira o sistema não precisa se preocupar com a lógica de criação de objetos, permitindo que ela evolua independente do resto.

Padrões Estruturais

Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy

Os Padrões Estruturais se preocupam em como as classes e objetos são compostos, ou seja, sua estrutura. O objetivo destes padrões e facilitar o design do sistema, melhorando as maneiras de relacionamento entre as entidades.

Padrões Comportamentais

Interpreter, Template Method, Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Stratefy, Visitor

Os Padrões Comportamentais atuam na distribuição das responsabilidades entre os objetos, ou seja, como eles se comportam. Estes padrões facilitam a comunicação entre os objetos, distribuindo as responsabilidades.

REVISITANDO A ORIENTAÇÃO A OBJETOS

A programação Orientada a Objetos é um paradigma bastante disseminado entre os desenvolvedores, assim cada pessoa acaba tendo seu próprio entendimento. Então, antes de falar sobre os padrões desse paradigma, vamos analisar as ideias do pensamento orientado a objetos e partir de um ponto comum.

Alan Kay cunhou o termo “Orientação a Objetos” em 1967 e é tido como o criador do paradigma. Em um email, que é a fonte de informação mais importante sobre o tema http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en, Dr. Kay explica quais foram suas motivações iniciais ao criar a Programação Orientada a Objetos.

Segundo sua definição, podemos entender o paradigma Orientado a Objetos em duas partes: 1) objetos seriam como células biológicas, que se comunicam apenas através de mensagens e 2) esconder os dados, pois cada objeto possui sua própria lógica para lidar com a informação sem precisar expô-las.

Ao definir uma classe é comum falar na “interface do objeto” como sendo a maneira como os objetos desta classe trocam mensagens, ou seja os seus métodos públicos. Essa interface esconde o estado interno do objeto e permite que o desenvolvedor foque nas interações, simplificando o entendimento do programa.

A primeira linguagem a aplicar esses conceitos foi Smalltalk, uma linguagem de tipo dinâmico onde não existem tipos primitivos e tudo é implementado como uma classe. Ao longo do desenvolvimento de novas linguagens, outras funcionalidades foram adicionadas, como por exemplo a herança e o polimorfismo.

As linguagens Orientada a Objetos mais recentes tendem a misturar conceitos e funcionalidades de diversos paradigmas, como por exemplo representar métodos como objetos, utilizar lambdas para passar blocos de código como parâmetros para outros métodos etc. Mas por trás de todas essas novas funcionalidades continua o pensamento de esconder os dados para facilitar a comunicação entre objetos.

Alguns Princípios de Design Orientado a Objetos

Com a grande adoção de linguagens Orientada a Objetos, surgiram vários princípios para guiar o design de sistemas. Esses princípios ajudam a organizar o código e facilitam a manutenção através de boas práticas sobre como escrever as interações entre os objetos.

O conjunto de princípios que se tornou mais famoso é o SOLID, criado por Robert C. Martin (também conhecido na comunidade como “Uncle Bob”). O problema que levou a criação deles foi a dificuldade de gerenciar dependências entre objetos e classes, especialmente quando a aplicação começa a crescer.

Segundo Robert, um código que não consegue fazer um bom gerenciamento de dependência se torna difícil de manter, frágil e não reutilizável. Em resumo, esses são os princípios e o que eles pregam:

  • Single Responsibility Principle (Princípio da Responsabilidade Única): Cada classe deve ter um, e apenas um, motivo para mudar;
  • Open Closed Principle (Princípio Aberto Fechado): Deve ser possível estender o comportamento de uma classe sem modificá-la;
  • Liskov Substitution Principle (Princípio da Substituição de Liskov): Classes derivadas devem ser compatíveis com sua classe base;
  • Interface Segregation Principle (Princípio da Segregação de Interface): Crie interfaces mínimas e específicas para o cliente;
  • Dependency Inversion Principle (Princípio da Inversão de Dependência): Dependa de abstrações ao invés de classes concretas.

Em seu site, Robert apresenta artigos dedicados a cada um dos princípio, com motivação, exemplos e aplicações. Além disso, outros princípios também podem ser encontrados lá e a leitura é recomendada para aprofundar o conhecimento no assunto: http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod. No meu blog, tenho uma série de posts dedicada aos princípios solid que também pode ajudar a entender melhor a importância deles: https://brizeno.wordpress.com/solid/.

Além do SOLID, também vale a pena explorar outros dois princípios de design Orientado a Objetos que estão fortemente presentes nos Padrões de Projeto:

  • Prefira Composição ao invés de Herança: ao herdar de uma classe estamos aumentando o nível de acoplamento entre elas, portanto é preferível compor objetos e criar interfaces para expor sua lógica;
  • Programe voltado a Interface e não a Implementação: ao desenvolver uma classe não pense em como ela vai funcionar, mas sim em como ela será utilizada. Exponha interfaces que façam sentido e simplificam seu uso.

Esses princípios foram especialmente citados aqui pois, ao refatorar o código e aplicar um padrão, estamos também seguindo os princípios de design Orientado a Objetos.