Open Closed Principle (OCP) - Flexível como os Vingadores
Tags: rails, ruby, solidprinciples, braziliandevs
Published: 2023-09-10 03:43:54

## Introdução
O Princípio Aberto/Fechado (OCP, na sigla em inglês) é uma das regras fundamentais para escrever um código sólido. Este princípio estabelece que as classes de software devem ser abertas para extensão, mas fechadas para modificação.

Imagine que cada Vingador tenha sua própria missão e habilidade especial. Quando um novo Vingador se junta à equipe, ele não muda a forma como os outros funcionam; ele simplesmente traz algo novo.

## Assemble!
![Assemble](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExcTkyemIwd2gxNmg0MDhwZTBmdHNhb2VyeDAyMDh0bGIyc2YwM3FjYSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/LOFT5Jd31ON1b5kLtP/giphy-downsized-large.gif)

Se você tiver uma classe que determina o que cada Vingador faz ao atacar e essa classe precisar ser alterada sempre que um novo Vingador chegar, você está descumprindo o OCP:

```ruby
class Vingador
  def initialize(tipo)
    @tipo = tipo
  end
  
  def atacar
    if @tipo == "CapitaoAmerica"
      puts "Lançando o escudo!"
    elsif @tipo == "Thor"
      puts "Lançando o martelo!"
    end
  end
end
```

Para corrigir isso, você pode usar **herança** ou **composição**.

```ruby
# Usando herança
class Vingador
  def atacar
    puts "Cada Vingador ataca de um jeito!"
  end
end

class CapitaoAmerica < Vingador
  def atacar
    puts "Lançando o escudo!"
  end
end

class Thor < Vingador
  def atacar
    puts "Lançando o martelo!"
  end
end
```

```ruby
# Usando composição
class AtaqueComEscudo
  def executar
    puts "Lançando o escudo!"
  end
end

class AtaqueComMartelo
  def executar
    puts "Lançando o martelo!"
  end
end

class Vingador
  def initialize(ataque)
    @ataque = ataque
  end
  
  def atacar
    @ataque.executar
  end
end

capitao_america = Vingador.new(AtaqueComEscudo.new)
thor = Vingador.new(AtaqueComMartelo.new)

capitao_america.atacar  # Saída: "Lançando o escudo!"
thor.atacar  # Saída: "Lançando o martelo!"
```

Vamos analisar o que podemos aprender com duas diferentes equipes de Vingadores.

![Team](https://media.giphy.com/media/3ornkaW4ikPkasJX20/giphy.gif)

## \#TeamHerança: A Equipe Rígida

Nessa equipe os Vingadores possuem uma regra estrita: todo novo membro deve ser capaz de voar e disparar lasers. Todo novo Vingador herda certas habilidades, mas também limitações. Se o Hulk entra para a equipe, teremos um problema: ele não voa nem dispara lasers. Ele tem suas próprias habilidades únicas. Cada herói está "preso" às regras da equipe.

- Acoplamento Forte: As classes filhas estão intimamente ligadas à classe pai. Qualquer mudança na classe pai pode ter efeitos indesejados nas classes filhas.
- Hierarquia Complexa: À medida que o projeto cresce, manter uma hierarquia de classes coerente pode se tornar um desafio.
- Rigidez: A herança torna difícil adicionar funcionalidades que não se encaixam na estrutura existente.

## \#TeamComposição: A Equipe Flexível

Imagine se os Vingadores aceitassem heróis com todo tipo de habilidade. Precisa de alguém que seja bom em espionagem? Chame a Viúva Negra. Precisa de alguém que possa manipular o tempo? Chame o Doutor Estranho. Cada herói pode ser adicionado à equipe com suas habilidades únicas. 

Você pode adicionar novas "peças" (classes ou métodos) ao seu projeto, dependendo do que você precisa. Cada herói pode ser ele mesmo, e a equipe pode se adaptar facilmente a novos desafios.

- Baixo Acoplamento: Cada classe ou componente é uma unidade independente que pode ser facilmente substituída ou atualizada.
- Alta Coesão: Cada classe tem uma única responsabilidade, tornando o código mais legível e manutenível.
- Flexibilidade Extrema: Novas funcionalidades podem ser adicionadas facilmente como novos componentes, sem afetar o sistema existente.

## Reflexões

A composição oferece mais flexibilidade do que sistemas com regras estritas. Se surgir uma nova ameaça, uma equipe flexível pode rapidamente incorporar um novo membro com habilidades específicas, evitando a necessidade de reavaliar todas as regras existentes.

Muitos desenvolvedores, incluindo eu, preferem a composição à herança para implementar o OCP. A composição promove baixo acoplamento, tornando mais fácil e menos arriscado adicionar novas funcionalidades. Em sistemas pouco acoplados, mudanças em uma parte não afetam as demais, facilitando o entendimento, o teste e a manutenção do código.

Essa modularidade é semelhante à forma como os Vingadores operam: cada herói pode funcionar de forma independente, mas também em conjunto quando necessário. Isso evita a complexidade e os riscos associados a sistemas fortemente acoplados, onde mudanças em uma parte afetam todo o sistema.

## Ah vida real
A herança permite estender classes de forma clara, mas cria acoplamento forte entre a classe base e suas subclasses, tornando o sistema menos adaptável e mais complexo para novos desenvolvedores.

Em contraste, a composição oferece grande flexibilidade. Em um sistema de pagamento online, por exemplo, você pode começar com uma API como o Stripe e facilmente adicionar outras como o PayPal. Isso é feito simplesmente criando uma nova classe com a mesma interface de pagamento (pense na "interface de pagamento" como um conjunto de regras ou instruções que todos os métodos de pagamento devem seguir, como "aceitar pagamento" ou "dar troco").

Embora a flexibilidade nem sempre seja necessária, ela se torna valiosa em um mundo imprevisível, permitindo que o sistema se adapte facilmente a novas circunstâncias.

## Conclusão
O OCP não é apenas uma regra técnica, mas uma filosofia de design que encoraja a preparação para o imprevisível. Ele nos ensina a construir sistemas tão flexíveis e independentes quanto os Vingadores, prontos para se adaptar a novas situações e desafios sem reestruturar o que já funciona bem.

A escolha entre herança e composição não é apenas uma questão técnica, mas também uma decisão estratégica que pode determinar o quão ágil e adaptável seu sistema será. Enquanto a herança nos aprisiona em uma estrutura predefinida, a composição nos dá as ferramentas para construir sistemas verdadeiramente modulares e de fácil manutenção.

Então, da próxima vez que você se encontrar diante de um desafio de programação, pergunte-se: "Como posso tornar esse sistema mais flexível e menos acoplado?" A resposta pode não apenas melhorar o seu código, mas também prepará-lo para um futuro cheio de possibilidades desconhecidas.