O princípio SRP (princípio de responsabilidade única) é um dos princípios fundamentais para escrever código suportado. Neste artigo, mostrarei como aplicar esse princípio usando o exemplo da linguagem PHP e a estrutura do Laravel.Freqüentemente, ao descrever o modelo de desenvolvimento do MVC, tarefas excessivamente grandes são atribuídas ao controlador. Obtendo parâmetros, lógica de negócios, autorização e resposta.Obviamente, em artigos e livros isso é descrito como um exemplo, mas geralmente é percebido como um plano de ação em projetos de trabalho. Essa abordagem inevitavelmente levará a um crescimento descontrolado de classe e complicará bastante o suporte ao código.Princípio da responsabilidade compartilhada
Por exemplo, tomaremos o tipo bastante grosseiro, mas geralmente atendido, do controlador "grosso".class OrderController extends Controller
{
public function create(Request $request)
{
$rules = [
'product_id' => 'required|max:10',
'count' => 'required|max:10',
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
$order = Order::create($request->all());
return response()->json($order, 201);
}
}
Neste exemplo, pode-se observar que o responsável pelo controle sabe muito sobre "fazer um pedido", também é encarregado de notificar o comprador e fazer a reserva de mercadorias.Nós nos esforçaremos para garantir que o controlador tenha apenas o controle de todo o processo e nenhuma lógica de negócios.Para começar, validaremos os parâmetros em uma classe Request separada.class OrderRequest extends Request
{
public function rules(): array
{
return [
'product_id' => 'required|max:10',
'count' => 'required|max:10',
];
}
}
E mova toda a lógica de negócios para a classe OrderServicepublic class OrderService
{
public function create(array $params)
{
$sms = new RuSms($appId);
$sms->send($number, $text);
}
}
Usando o Service Container, implementaremos nosso serviço no controlador.Como resultado, temos um controlador "fino".class OrderController extends Controller
{
protected $service;
public function __construct(OrderService $service)
{
$this->service = $service;
}
public function create(OrderRequest $request)
{
$this->service->create($request->all());
return response()->noContent(201);
}
}
Já está melhor. Toda a lógica de negócios foi movida para o serviço. O controlador conhece apenas as classes OrderRequest e OrderService - o conjunto mínimo de informações necessárias para realizar seu trabalho.Mas agora nosso serviço também precisa ser refatorado. Vamos tirar a lógica de enviar sms para uma classe separada.class SmsRu
{
protected $appId;
public function __constructor(string $appId)
{
$this->appId = $appId;
}
public function send($number, $text): void
{
}
}
E implementá-lo através do construtorclass OrderService
{
private $sms;
public function __construct()
{
$this->sms = new SmsRu($appId);
}
public function create(array $params): void
{
$this->sms->send($nubmer, $text);
}
}
Já é melhor, mas a classe OrderService ainda sabe muito sobre o envio de mensagens. Talvez seja necessário substituir o provedor de mensagens no futuro ou adicionar testes de unidade. Continuamos refatorando adicionando a interface SmsSender e especificando SmsRu por meio do provedor SmsServiceProvider .interface SmsSenderInterface
{
public function send($number, $text): void;
}
class SmsServiceProvider implements ServiceProviderInterface
{
public function register(): void
{
$this->app->singleton(SmsSenderInterface::class, function ($app) {
return new SmsRu($params['app_id']);
});
}
}
Agora o serviço também é liberado de detalhes desnecessáriosclass OrderService
{
private $sms;
public function __construct(SmsSenderInterface $sms)
{
$this->sms = $sms;
}
public function create(): void
{
$this->sms->send($nubmer, $text);
}
}
Arquitetura Orientada a Eventos
O envio de mensagens não faz parte do processo básico de criação de pedidos. O pedido será criado independentemente da mensagem enviada; também é possível no futuro a opção de cancelar alertas de SMS será adicionada. Para não sobrecarregar o OrderService com detalhes de notificação desnecessários, você pode usar os Observadores do Laravel . Uma classe que rastreará eventos com um determinado comportamento do nosso modelo de pedidos e atribuirá a ele toda a lógica da notificação do cliente.class OrderObserver
{
private $sms;
public function __construct(SmsSenderInterface $sms)
{
$this->sms = $sms;
}
public function created(Order $order)
{
$this->sms->send($nubmer, $text);
}
Não se esqueça de registrar o OrderObserver no AppServiceProvider .Conclusão
Entendo que estou descrevendo coisas bastante banais neste post, mas queria mostrar como esse princípio é implementado na estrutura do Laravel.O princípio da SPR é um dos mais importantes e abre o caminho para o resto. É necessário usar, especialmente porque a estrutura do Laravel fornece todas as ferramentas necessárias.