Principios SOLID. Single responsibility principle


Principios SOLID. Single responsibility principle

Enfrentamos el primer principio de los conceptos SOLID. El principio de responsabilidad única y veremos un ejemplo de este en PHP.



Algo de historia


SOLID es un acrónimo (compuesto de más acrónimos :P) generado por Robert C. Martín a comienzo de la década de 2000 que representa cinco principios básicos de la Programación Orientada a Objetos y el diseño.

  • S - Single responsibility principle (Principio de Responsabilidad Única)
  • O - Open/Closed principle (Principio Abierto/Cerrado)
  • L - Liskov substitution principle (Principio de Sustitutcion de Liskov)
  • I - Interface segregation principle (Principio de Separación de Interfaces)
  • D - Dependency inversion principle (Principio de Inversión de Dependencias)


Estos cinco principios ayudan a escribir código mas legible, mejor estructurado y modular, permitiendo que el software sea, entre otras características, escalable y mantenible en el tiempo.

No es fácil entenderlos de primera y mucho menos aplicarlos siempre, se requiere practica, pero por sobre todo debes entender que estos principios no son una regla a seguir pero que deben ser considerados para obtener un código de calidad.

Principio de Responsabilidad Única


Un objeto sólo debe tener un motivo para cambiar, lo que significa que sólo debe tener una tarea principal.

Principio de responsabilidad única.

Un objeto debe tener una razón de ser y esta debe estar encapsulada en una clase. Puede tener múltiples comportamientos pero cada uno de estos deben estar relacionados con la razón de ser de la clase.

Conociendo el problema


Supondremos que necesitamos calcular las áreas de varias figuras geométricas para alguna aplicación que estamos construyendo, y necesitamos sumar todas estas áreas.
Así en primera instancia, necesitaríamos una clase por cada figura y una clase para realizar el calculo pedido (calcular el área por figura y entregar la suma de estas áreas).

Código de ejemplo en PHP


Según el problema y pensando que por ahora tenemos solo dos objetos, un círculo y un cuadrado, podríamos construir las siguientes clases para ambos
/* Clase Circulo */
namespace Blockpc\Clases;
Class Circulo {
private $radio;
public function __construct(int $radio) {
$this->radio = $radio;
}
public function getRadio() {
return $this->radio;
}
}
/* Clase Cuadrado */
namespace Blockpc\Clases;
class Cuadrado {
private $lado;
public function __construct(int $lado) {
$this->lado = $lado;
}
public function getLado() {
return $this->lado;
}
}

La clase encargada de realizar los cálculos, que llamaremos AreaCalculador, quedaría.
/* Clase AreaCalculador */
namespace Blockpc\Clases;
class AreaCalculador {
private $figuras;
public function __construct(...$figuras) {
$this->figuras = $figuras;
}
private function suma() {
foreach ($this->figuras as $figura) {
if(is_a($figura, 'Blockpc\Clases\Cuadrado')){
$area[] = pow($figura->getLado(), 2);
} elseif (is_a($figura, 'Blockpc\Clases\Circulo')){
$area[] = pi() * pow($figura->getRadio(), 2);
} else {
throw new \Exception("Se esperaba un objeto figura!");
}
}
return array_sum($area);
}
public function salida() {
return "<h3>Suma de todas las áreas: {$this->suma()}</h3>";
}
}

Observemos que las clases Círculo y un Cuadrado tienen una simple razón de ser, que es la de "construir" una figura, no hacen nada mas ni nada menos.
En cambio la clase AreaCalculador implementa en la función suma() dos responsabilidades, calcular las áreas dentro del ciclo foreach y retornar la suma de estas. Tener dos responsabilidades afecta el principio que queremos aplicar.

Solución


Implementamos dos clases, para separar ambos cálculos, la clase AreaCalculadorPRU y la clase SumaCalculadorPRU.
(PRU hace referencia al Principio de Responsabilidad Única que estudiamos)
/* Clase AreaCalculadorPRU */
namespace Blockpc\Clases;
class AreaCalculadorPRU {
private $figuras;
private $area;
public function __construct(...$figuras) {
$this->figuras = $figuras;
$this->area = [];
}
private function calcularAreas() {
foreach ($this->figuras as $figura) {
if(is_a($figura, 'Blockpc\Clases\Cuadrado')){
$this->area[] = pow($figura->getLado(), 2);
} elseif (is_a($figura, 'Blockpc\Clases\Circulo')){
$this->area[] = pi() * pow($figura->getRadio(), 2);
} else {
throw new \Exception("Se esperaba un objeto figura!");
}
}
}
public function getAreas() {
$this->calcularAreas();
return $this->area;
}
}
/* Clase SumaCalculadorPRU */
namespace Blockpc\Clases;
class SumaCalculadorPRU {
private $areas;
public function __construct(array $areas) {
$this->areas = $areas;
}
public function getSuma() {
$suma = array_sum($this->areas);
return "<h3>Suma de todas las áreas: {$suma}</h3>";
}
}


Implementado el principio de responsabilidad única


En un archivo index.php tendríamos:
/* index.php */
$circulo = new Blockpc\Clases\Circulo(4);
$cuadrado = new Blockpc\Clases\Cuadrado(4);
/*
* Primer ejemplo funcional
* Construido sin aplicar el Principio de responsabilidad única
**/
$areas = new Blockpc\Clases\AreaCalculador($circulo, $cuadrado);
echo $areas->salida(); /* Suma de todas las áreas: 66.265482457437 */
/*
* Tercer ejemplo funcional
* Aplicando el Principio de responsabilidad única
**/
$area = new Blockpc\Clases\AreaCalculadorPRU($circulo, $cuadrado);
$areas = $area->getAreas();
$suma = new Blockpc\Clases\SumaCalculadorPRU($areas);
echo $suma->getSuma();/* Suma de todas las áreas: 66.265482457437 */


Ultimas consideraciones


En el archivo adjunto les dejo el código fuente que utilice. El archivo index.php viene con una clase Autoload para la carga de clases siguiendo el estándar PSR-4
Les dejo un enlace con el articulo original en Ingles acá

Y por acá otros ejemplos.

El código fuente utilizado lo descargas desde acá

Saludos y hasta el próximo articulo.

Etiquetas solid php

Ultima actualización Miércoles 02 de Mayo, 2018




Agregar Comentario