Uma classe precisa ter uma única responsabilidade e apenas um motivo para alterá-la. É o que informa o SRP – Single Responsability Principle (Principio da Responsabilidade única), que é um dos componentes do SOLID.
O que é o SOLID
O SOLID é um conjunto de orientações para você possa trabalhar melhor com a Orientação a Objeto.
- Single Responsability Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
O S, que seria o Single Responsability Principle, que iremos tratar nesse artigo. Tende a evitar as classes chamadas God Class, que são classes que fazem tudo, e com isso podem ser problemáticas. Se você precisa ficar alterando vários pontos da sua classe, tem uma maior possibilidade de dar algum bug.
A aplicação do SRP (Single Responsability Principle)
Precisamos criar um cadastro de contato básico, apenas nome e e-mail, e a classe precisará realizar o cadastro e enviar um e-mail para o contato que foi cadastrado.
Segue a classe:
<?php
class Contact
{
public $name;
public $email;
public function insert()
{
$pdo = new \PDO("mysql:host=localhost;dbname=site", "root", "");
$sql = "INSERT INTO contacts SET name = :name, email = :email";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':name', $this->name);
$stmt->bindValue(':email', $this->email);
$stmt->execute();
$this->sendEmail();
}
public function sendEmail()
{
mail($this->email, "Enviar email", "Contato");
}
}
Na classe acima, ela tem mais de uma responsabilidade: ela é responsável pelos dados, por fazer persistência, por conectar ao banco de dados e enviar um e-mail.
Ela tenta se responsabilizar por todas as etapas.
Para utilizar, seria assim:
<?php
$contact = new Contact();
$contact->name = 'David';
$contact->email = '[email protected]';
$contact->insert();
Apesar da execução parecer simplificada, a classe possui vários problemas: a falta de encapsulamento dos dados, conexão do banco de dados definida dentro da classe (se precisarmos alterar os dados da conexão ou se precisarmos criar um template para o e-mail, teremos que mexer na mesma classe).
Essa classe é bem problemática, porque falta coesão e ela é muito acoplada, não permitindo variações ou utilizações separada dos itens.
E com isso, é preciso separar essas responsabilidades. Vamos refatorar a classe, e separar cada responsabilidade em classes distintas.
<?php
class Contact
{
private $name;
private $email;
public function setName($name)
{
$this->name = $name;
}
public function setEmail($email)
{
$this->email = $email;
}
public function getName()
{
return $this->name;
}
public function getEmail()
{
return $this->email;
}
}
<?php
class ContactSendMail
{
private $contact;
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
public function shoot()
{
mail($this->getEmail(), "Enviar email", "Contato");
}
}
<?php
class ContactDAO
{
private $db;
public function __construct(\PDO $pdo)
{
$this->db = $pdo;
}
public function insert(Contact $contact)
{
$sql = "INSERT INTO contacts SET name = :name, email = :email";
$stmt = $this->db->prepare($sql);
$stmt->bindValue(":name", $contact->getName());
$stmt->bindValue(":email", $contact->getEmail());
return $stmt->execute();
}
}
Refatoramos a nossa classe, e criamos 3 classes:
- Uma classe Contact, que é entidade, responsável por representar um Contato.
- Uma classe ContactSendMail que é responsável por disparar o e-mail.
- Uma classe ContactDAO que é responsável pela interação com Banco de dados.
Como deve ser utilizada:
<?php
//Conexão com banco de dados com PDO
$pdo = new \PDO("mysql:host=localhost;dbname=site", "root", "");
/*Define os dados a serem inserido*/
$contact = new Contact();
$contact->setName('David');
$contact->setEmail('[email protected]');
//Classe que será responsavel pelas operações no banco de dados
$contactDAO = new ContactDAO($pdo);
if($contactDAO->insert($contact)) {
//Classe responsável por disparar um e-mail
$send = new ContactSendMail($contact);
$send->shoot();
}
Conclusão
Cada classe tem o nome coerente do que é responsável, facilitando assim a forma de trabalhar com elas.
É importante ressaltar, que a questão não é ter um método por classe, e sim que os métodos dessa classe sejam coerentes com que o que classe se propõe a fazer.
Espero que o artigo tenha ajudado, e até a próxima.