development, solid,

Princípios SOLID: OCP e sopa de letrinhas

Leonardo Rifeli Leonardo Rifeli Follow Dec 05, 2017 · 4 mins read
Princípios SOLID: OCP e sopa de letrinhas
Share this

Este é o segundo post de uma série onde abordaremos todos os cinco princípios do SOLID. Neste, falaremos sobre “Open closed principle”, abreviado por OCP, e significa literalmente “Princípio aberto-fechado”.

O primeiro post foi sobre “Single responsibility principle”, abreviado por SRP, e você pode ler aqui.

Para começar: falar de SOLID é falar de programação orientada a objetos e design (OOD). Tendo isso em mente, o princípio aberto-fechado traz uma perspectiva importante: os participantes precisam ser abertos para extensão e fechadas para modicação.

Antes de tudo, os conceitos SOLID estão atrelados?

De maneira ou outra, sim! No primeiro post, discutimos sobre SRP onde os participantes devem possuir somente uma razão para mudança; adicionar uma nova feature irá violar tanto SRP como OCP. Ou seja, quanto maior o número de responsabilidade de um participante, maior a probabilidade de violar OCP.

Portanto, um código que segue SRP tende a estar mais próximo de seguir OCP, por consequência.

Tá! E o que é ser aberto para extensão?

Após um software estar em produção, há grande probabilidade de sofrer alterações, evoluir, ter novas features, etc. OCP defende que à partir do momento que o software está em produção, os participantes em questão não poderão sofrer modificações, diminuindo a chance de algum bug ser causado.

Aberto para extensão significa que não podemos modificar o participante que já está em produção e sim exterder as suas funcionalidades atuais e implementar as novas features.

Ou seja, o OCP nos força a desenvolver códigos extensíveis, tornando-os escaláveis e não editáveis.

Com isso, é importante ter a definição de herança bem clara. Você pode ler um pouco sobre no artigo Herança ou Composição.

Problemas da violação do OCP

  • Quebrar outros princípios SOLID;
  • Maior probabilidade de causar bug;
  • Um código não escalável e provavelmente menos extensível;
  • Entre outros.

Exemplos

Seguindo o mesmo padrão do primeiro post, os exemplos serão exibidos somente com as assinaturas, para refornçar a ideia que Uncle Bob traz, de que a implementação dos métodos é irrelevante para a análise. Somente com as assinaturas, conseguimos perceber se existe (ou não) a violação do princípio.

Exemplo com violação

Observe o exemplo abaixo, onde temos a classe Debit e ela precisará debitar um determinado valor de um tipo de débito.

<?php

namespace Leonardo\Rifeli\Article\Business;

use namespace Leonardo\Rifeli\Article\Business\DebitType;

class Debit
{
    public function execute(int value, DebitType debitType) { }
}

?>

Com o exemplo acima, será necessário ter condições para controlar e implementar as regras de negócio dos tipos de débitos. Considerando que tenhamos os tipos: Savings e CheckingAccount, teríamos condições para estes dois tipos e caso novos tipos de détibo surgem, violaríamos OCP.

Exemplo sem violação

No exemplo abaixo, a classe Debit virará uma abstract class, e os tipos de conta, serão classes derivadas de Debit.

<?php

namespace Leonardo\Rifeli\Article\Business\Abstract;

abstract class Debit
{
    abstract public function execute(int value) { }
}

?>

Caso novos tipos de débito surgem, basta extender Debit e executar a transação com as regras de negócio necessárias.

Com isso, a cada novo tipo, teremos novos códigos e não códigos alterados.

<?php

namespace Leonardo\Rifeli\Article\Business;

use Leonardo\Rifeli\Article\Business\Abstract\Debit;

class CheckingAccount extends Debit
{
    public function execute(int value) { }
}

?>

Para ampliar nossos exemplo, podemos criar uma classe SomeDebit tendo os métodos setDebit e execute, conforme exemplo abaixo.

<?php

namespace Leonardo\Rifeli\Article\Business;

use Leonardo\Rifeli\Article\Business\Abstract\Debit;

class SomeDebit
{
    private $debit;

    public function setDebit(Debit $debit)
    {
        $this->debit = $debit;
    }

    public function execute(int value)
    {
        return $this->debit->execute(value);
    }
}

?>

Conforme novos tipos forem surgindo, basta criá-lo extendendo Debit, e utilizar o SameDebit para executar. Aqui, no final, estamos aplicando o padrão de projeto Strategy.

Referências

Conclusão

OCP reforça que pensar em orientação a objetos é pensar primeiro na abstração e depois na implementação em si. Vale lembrar que softwares OO evoluem por meio de novos códigos, e não por edições.

Podemos continuar as discussões sobre este princípio nos comentários?

Compartilhe seus aprendizados.

Join Newsletter
Get the latest news right in your inbox. We never spam!
Leonardo Rifeli
Written by Leonardo Rifeli Follow
Head of Engineering & Partner at @Reviewr and studying mathematics.