Princípios de Design de Software – Open/Closed Principle

Continuando a série sobre os Princípios SOLID, vamos falar um pouco sobre o “O”, que significa Open/Closed Principle. Mais uma vez, será usado como guia principal um texto de Robert C. Martin [1], no entanto vou trazer mais algumas referências, pois achei que o post anterior ficou pobre em referências.

Open/Closed Principle

Este princípio pode ser definido como [2]:

“Entidades de software (classes, módulos, funções, etc) devem ser abertas para extensão mas fechadas para modificações” – Bertrand Meyer (1988)

O princípio basicamente sugere que as suas classes (ou demais entidades) sejam flexíveis a mudanças, para que estas não afetem muitas partes do sistema. Conforme descrito em [1], todo sistema sofre mudanças ao longo do seu ciclo de vida, e isto precisa está sempre na mente dos desenvolvedores que esperem que o sistema dure mais do que sua primeira versão.

O que não quer dizer que é preciso prever alterações (as Metodologias Ágeis estão ai para provar que adivinhar não funciona), mas que, com um pouco de cuidado e atenção no design do código, é possível reduzir o impacto de mudanças ao longo do sistema.

O princípio sugere então que, se um código está funcionando, e uma mudança precisa ser feita, é melhor adicionar novos códigos do que alterar entidades que já estão funcionando [1]. O design deve ser feito de tal maneira que, adicionar funcionalidades mantenha o máximo de código existente [4]. Código existente se refere a código que funciona, ou seja, código que já foi testado e aprovado, e que não precisa ser alterado (ou ao menos não deveria).

Em [1] a abstração é apontada como ponto chave para seguir o padrão. Para não cair apenas na teoria vamos analisar o exemplo mostrado em [1]. O problema consiste em uma aplicação que precisa desenhar formas geométricas (círculos e quadrados) em uma GUI.

Fazer então um método que desenhe as formar utilizando if’s para identificar qual o tipo de forma a ser desenhada é obviamente um mal design, como pode ser visto no código a seguir:

void DrawAllShapes(ShapePointer list[], int n)
{
  int i;
  for (i=0; i<n; i++)
  {
    struct Shape* s = list[i];
    switch (s->itsType)
    {
    case square:
      DrawSquare((struct Square*)s);
    break;
    case circle:
      DrawCircle((struct Circle*)s);
    break;
    }
  }
}

Acrescentar uma nova forma causaria uma modificação neste switch e em todos os outros switch’s espalhados pelo código do sistema. A solução seria utilizar uma classe base abstrata, que define o método de desenho, e definir as formas como subclasses que implementem este método, assim garantindo que o sistema é fechado para mudanças nas formas, como pode ser visto a seguir:

void DrawAllShapes(Set<Shape*>& list)
{
  for (Iterator<Shape*>i(list); i; i++)
     (*i)->Draw();
}

Ainda em [1], Martin comenta sobre como é possível fechar o sistema para outras mudanças, como a ordem em que as figuras são desenhadas. Apesar de simples, o exemplo acima mostra bem a importância deste princípio.

Seguir esse princípio traz um dos maiores benefícios propostos pela orientação a objetos: a facilidade de manutenção [1]. No entanto, como todo princípio, o OCP torna o sistema mais flexível, mas introduz complexidade e abstrações ao sistema, devendo assim ser utilizado apenas aonde é mais propenso a mudanças [4].

Padrões de Projeto

O exemplo comentado deixa bem claro que a aplicação do padrão Factory Method evitaria problemas com a alteração das formas. E o Factory Method é um bom exemplo de uso do princípio OCP, pois ele fecha o sistema a alterações nas classes produtos, deixando extensível a adição de novas classes.

Outro bom exemplo deste princípio é o padrão Template Method, pois ele fecha o sistema a mudanças no algoritmo, mas permite extensões, através dos pontos gancho que são definidos nas suas subclasses. Desta forma, adicionar um novo método apenas necessita que uma nova classe herde o comportamento da classe base e defina os pontos que precisam ser alterados.

O padrão State dá uma grande flexibilidade ao sistema, permitindo a adição de novos estados apenas utilizando a herança. No entanto, ao adicionar um novo estado, dependo da implementação, é preciso alterar a parte do código que decide qual o próximo estado. Neste caso, apesar de não ser muito bem fechado para mudanças de estados, o padrão State minimiza a necessidade de alterações.

Já o padrão Strategy oferece um fechamento muito bom a mudanças nos comportamentos, pois o código cliente utiliza apenas uma interface, permitindo variar sem grandes alterações o comportamento a ser utilizado.

Se gostou do post compartilhe com seus amigos e colegas, senão, comente o que pode ser melhorado. Possui alguma outra opinião ou alguma informação adicional? Comenta ai! 😀

Referências:

[1] http://www.objectmentor.com/resources/articles/ocp.pdf

[2] http://blog.lambda3.com.br/2009/09/usando-o-principio-abertofechado-open-closed-principle-ocp/

[3] http://en.wikipedia.org/wiki/Open/closed_principle

[4] http://www.oodesign.com/open-close-principle.html

Anúncios

Um comentário sobre “Princípios de Design de Software – Open/Closed Principle

  1. […] responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion […]

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s