DEV Community

loading...

Princípios SOLID: o que são e como aplicá-los no PHP/Laravel (Parte 02 - Aberto-fechado)

lucascavalcante profile image Lucas ・3 min read

Dando continuidade à série de artigos sobre princípios SOLID, hoje vou falar sobre o segundo dos princípios.

Open-closed Principle

(Princípio Aberto-fechado)

Objetos ou entidades devem ser abertas para extensão, mas fechadas para modificação.

Em outras palavras, se eu tenho uma classe genérica que atende a diversos tipos de perfis, ao invés de sair fazer condicionais para cada caso, podemos criar especializações dessa classe, e em cada uma delas eu coloco o que atende aquele perfil.

Vamos continuar o exemplo que eu usei no artigo anterior, onde nós temos 2 tipos de User, o Employee e o Contractor.

Você pode ver aqui que eu criei 2 Repositories, um para cada tipo de usuário, e em ambas eu criei o método save() executando exatamente a mesma coisa. (no final do artigo eu expliquei que usei dessa maneira para facilitar o entendimento da separação de responsabilidades)

Então, vamos melhorar esse código.

class BaseRepository
{
    protected $obj;

    protected function __construct(object $obj)
    {
        $this->obj = $obj;
    }

    public function all(): object
    {
        return $this->obj->all();
    }

    public function find(int $id): object
    {
        return $this->obj->find($id);
    }

    public function findByColumn(string $column, $value): object
    {
        return $this->obj->where($column, $value)->get();
    }

    public function save(array $attributes): bool
    {
        return $this->obj->insert($attributes);
    }

    public function update(int $id, array $attributes): bool
    {
        return $this->obj->find($id)->update($attributes);
    }
}

Criei uma classe BaseRepository que como o próprio nome diz, serve como base para classes especialistas, contendo os métodos que são genéricos a todas as classes que irão estendê-la.

Vamos criar as classes filhas (ou especialistas).

class EmployeeRepository extends BaseRepository
{
    protected $employee;

    public function __construct(Employee $employee)
    {
        parent::__construct($employee);
    }
}

class ContractorRepository extends BaseRepository
{
    protected $contractor;

    public function __construct(Contractor $contractor)
    {
        parent::__construct($contractor);
    }
}

Se as classes EmployeeRepository e ContractorRepository não tiverem nenhuma especificidade, basta criá-las apenas com o construtor chamando a classe pai que todos os métodos irão funcionar. Na camada de Service quando formos fazer a injeção de dependência, injetamos a classe especialista.

Mas utilizando alguns princípios da orientação a objetos, vamos fazer algo específico para cada uma delas.

class EmployeeRepository extends BaseRepository
{
    protected $employee;

    public function __construct(Employee $employee)
    {
        parent::__construct($employee);
    }

    public function all(): object
    {
        $except = [3,17,22];
        return $this->employee->whereNotIn('id', $except)->get();
    }
}

class ContractorRepository extends BaseRepository
{
    protected $contractor;

    public function __construct(Contractor $contractor)
    {
        parent::__construct($contractor);
    }

    public function save(array $attributes, int $hoursPerWeek): bool
    {
        $attributes['hours_per_week'] = $hoursPerWeek;
        return $this->contractor->insert($attributes);
    }
}

Na classe EmployeeRepository eu fiz uma sobreposição do método all() onde quase tudo é igual à classe pai (nome, parâmetros, retorno) exceto a implementação.

Na classe ContractorRepository eu fiz uma sobrecarga do método save() onde o nome do método é o mesmo da classe pai, mas a quantidade e/ou tipo dos parâmetros é diferente.

Dessa forma consegui deixar ambas as classes mais especializadas sem interferir na classe pai, ou perder suas características.

Espero que tenha gostado. No próximo artigo da série vou falar sobre o Liskov Substitution Principle (Princípio da Substituição de Liskov)

Dúvidas e feedbacks são sempre bem-vindos.

Discussion (3)

pic
Editor guide
Collapse
tiagodev profile image
Tiago Vieira

Ótimo conteúdo Lucas!

Collapse
kadudesouza profile image
Kadu de Souza

Muito bom, Lucas! Aguardando os próximos artigos.

Collapse
devinicius profile image
Vinicius Pereira de Oliveira

Conteúdo de ótima qualidade, isso abriu minha mente de um jeito incrível, muito obrigado Lucas por compartilhar um conteúdo tão importante