Princípios SOLID: o que são e como aplicá-los no PHP/Laravel (Parte 04 - Segregação de Interface)
Tags: php, solid, architecture, laravel
Published: 2020-11-12 19:22:29

Depois de um longo hiato, estou retomando a série dos príncipios SOLID, trazendo o quarto dos princípios.

# Interface Segregation Principle
_(Princípio da Segregação de Interface)_

> Uma classe não deve ser forçada a implementar interfaces que não irá utilizar.

Abstração é o coração da orientação a objetos. Em PHP, nós conseguimos alcançar um nível de abstração utilizando interfaces e classes abstratas.

Mas, antes, vamos dar um passo atrás: o que é interface?

Interface é um conjuntos de abstrações que todas as classes que a implementam deve seguir. Cada método adicionado na interface é uma assinatura, e a partir do momento que uma classe a implementa, esta fica obrigada a adicionar todas as assinaturas previamente criadas na interface.

Partindo deste princípio, parece óbvio que uma classe não deva ser forçada a implementar algo que não irá usar. Mas nesse artigo, você verá que este princípio é muito fácil de violar.

Seguindo o nosso exemplo de _Employees_ e _Contractors_, até o [terceiro post da série](https://dev.to/lucascavalcante/principios-solid-o-que-sao-e-como-aplica-los-no-php-laravel-parte-03-substituicao-de-liskov-2m9n) eu criei uma classe chamada `UserService` que injeta os _repositories_ para os dois tipos de usuário.

Vamos fazer uma pequena alteração, a partir de agora será um _service_ para cada tipo de usuário.

```php
class EmployeeService
{
  protected $employeeRepository;

  public function __construct(EmployeeRepository $employeeRepository)
  {
    $this->userRepository = $userRepository;
  }
}

class ContractorService
{
  protected $contractorRepository;

  public function __construct(ContractorRepository $contractorRepository)
  {
    $this->contractorRepository = $contractorRepository;
  }
}
```

Dessa maneira eu terei duas classes que irão implementar a mesma interface `UserInterface`.

```php
interface UserInterface
{
  public function register(array $attributes, UserRepository $userRepository);
  public function calcWorkedHours(array $hours);
}
```

Interface criada com a assinatura do método `register` (que foi criado nos posts anteriores), e agora adicionei o método `calcWorkedHours` que será um método útil para o usuário do tipo _Contractor_ onde as horas dele serão calculadas para gerar o pagamento no fim do mês.

Vamos implementar a interface nos dois _services_.

```php
class EmployeeService implements UserInterface
{
  public function register(array $attributes, UserRepository $userRepository)
  {
    // implementação do código
  }
}

class ContractorService implements UserInterface
{
  public function register(array $attributes, UserRepository $userRepository)
  {
    // implementação do código
  }

  public function calcWorkedHours(array $hours)
  {
    // implementação do código
  }
}

```

Dessa maneira nós vamos ter um erro na classe `EmployeeService` pois ela implementa a `UserInterface` mas não usa o método `calcWorkedHours`.

Uma maneira errada de resolver isso seria implementar o método, mas sem nenhuma implementação dentro do escopo.

A maneira correta seria criar duas interfaces e implementá-las onde for necessário.

```php
interface UserInterface
{
  public function register(array $attributes, UserRepository $userRepository);
}

interface ContractorInterface
{
  public function calcWorkedHours(array $hours);
}

```

E após criar as duas interfaces, as classes já poderiam escolher quem implementar.

```php
class EmployeeService implements UserInterface
{
  public function register(array $attributes, UserRepository $userRepository)
  {
    // implementação do código
  }
}

class ContractorService implements UserInterface, ContractorInterface
{
  public function register(array $attributes, UserRepository $userRepository)
  {
    // implementação do código
  }

  public function calcWorkedHours(array $hours)
  {
    // implementação do código
  }
}

```

Dessa maneira, não obrigamos nenhuma classe a implementar algo que não irá utilizar. Sendo assim, não violamos o princípio da segregação de interface. :)

Quando tentamos entender apenas a teoria dos princípios, parecem bem mais complicados do que realmente são.

No próximo, e último, artigo da série vou falar sobre o Dependency Inversion Principle (Princípio da Inversão de Dependência).

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