DEV Community

Lucas Cavalcante
Lucas Cavalcante

Posted on

Princípios SOLID: o que são e como aplicá-los no PHP/Laravel (Parte 04 - Segregação de Interface)

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 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.

class EmployeeService
{
  protected $employeeRepository;

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

class ContractorService
{
  protected $contractorRepository;

  public function __construct(ContractorRepository $contractorRepository)
  {
    $this->contractorRepository = $contractorRepository;
  }
}
Enter fullscreen mode Exit fullscreen mode

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

interface UserInterface
{
  public function register(array $attributes, UserRepository $userRepository);
  public function calcWorkedHours(array $hours);
}
Enter fullscreen mode Exit fullscreen mode

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.

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
  }
}

Enter fullscreen mode Exit fullscreen mode

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.

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

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

Enter fullscreen mode Exit fullscreen mode

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

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
  }
}

Enter fullscreen mode Exit fullscreen mode

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.

Discussion (6)

Collapse
julianaferreira91 profile image
Juliana

Estou ansiosa pelo próximo item da série, gostei muito.

Collapse
lucascavalcante profile image
Lucas Cavalcante Author
Collapse
brunofernandesdev profile image
BrunoFernandesDev

Oi Lucas, nao deixe de postar o 5 item da serie, gostei muito das suas explicações. Abraço

Collapse
lucascavalcante profile image
Lucas Cavalcante Author

Agora em Janeiro sai. 😎

Collapse
iagocalazans profile image
Iago Calazans

Aguardando! hehehe

Thread Thread
lucascavalcante profile image
Lucas Cavalcante Author

Hahahaha, demorou mas saiu: dev.to/lucascavalcante/principios-...