Вы находитесь на странице: 1из 13

22/03/13 [SRP] Principio de responsabilidad única

[SRP] Principio de
responsabilidad única

Descripción general

Principios del diseño orientado a objetos; Principios SOLID;


[SRP] Principio de responsabilidad única
"Cada objeto en el sistema deben tener una simple
responsabilidad, y todos los servicios de los objetos deben
cumplir con esa simple responsabilidad"

[TOC] Tabla de Contenidos

[SRP] Principio de responsabilidad única


Los cinco principios SOLID
[SRP] Principio de responsabilidad única
Veamos un ejemplo típico de violación del SRP:
Detectando responsabilidades
Separando responsabilidades
Otro Ejemplo
Una forma de probar este principio
Ampliando el abanico de "responsabilidades"
Conclusión
Referencia Bibliográfica

↑↑↑
[SRP] Principio de
responsabilidad única

↑↑↑
jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 1/13
22/03/13 [SRP] Principio de responsabilidad única

Los cinco principios SOLID

Principio de Responsabilidad Única (SRP – Single


Responsibility Principle)
Principio Abierto-Cerrado (OCP – Open Closed Principle)
Principio de Sustitución de Liskov (LSP - Liskov
Substitution Principle)
Principio de Segregación de Interfaces (ISP - Interface
Segregation Principle)
Principio de Inversión de Dependencia (DIP – Dependency
Inversion Principle)

↑↑↑
[SRP] Principio de responsabilidad única

El Principio de responsabilidad única (Single Responsability


Principle - SRP) fue acuñado por Robert C. Martin en un artículo
del mismo título y popularizado a través de su conocido libro
[patrones Gof]. SRP tiene que ver con el nivel de acoplamiento
entre módulos dentro de la ingeniería del software.

Este principio nos viene a decir que una clase sólo debería
tener una única razón para cambiar.

"Una clase debe tener una única razón para cambiar."

En términos prácticos, este principio establece que:

"Una clase debe tener una y solo una única causa por
la cual puede ser modificada."
"Cada clase debe ser responsable de realizar una
actividad del sistema

Lo que trata de decirnos este principio es que debemos huir de


aquellas clases monolíticas que aglutinen varias
responsabilidades. Pero, ¿qué es una responsabilidad? Desde
el punto de vista de SRP se podría decir que una
responsabilidad en una clase es una razón para cambiar esa
clase. Es decir, si encontramos que hay más de una razón por
la que una clase pueda cambiar entonces es que esa clase
tiene más de una responsabilidad.

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 2/13
22/03/13 [SRP] Principio de responsabilidad única

¿Y no sería más sencillo decir que una clase debería tener una
sola razón para existir en lugar de para cambiar? Cuidado,
porque esto nos podría llevar a hacer muy malos diseños de
sistemas. Llevado al pie de la letra podría encontrarme con
cientos de clases en mi sistema, cada una con una única
función. Lo que haría al sistema nada fácil de mantener.

El punto clave que nos dice las razones por la que una clase
puede cambiar va a depender del contexto en el que se va a
dar uso a esa clase. Pongamos por ejemplo una clase que
represente al motor de un coche. ¿Necesitamos conocer el
régimen de revoluciones del motor?, ¿el peso?, ¿número de
cilindros?, ¿presión del inyector de gasolina?, ¿o lo que nos
interesa es simplemente poder arrancarlo y esperar que haga
andar a un coche para llevaros de un sitio a otro? La respuesta
a estas preguntas va a depender del contexto en el cual
usemos la clase motor. No va a tener las mismas necesidades
sobre esta clase un fabricante de coches que un usuario que
usa el coche para ir de un sitio a otro. El fabricante de coches
va a notar un número mayor de responsabilidades en el motor
que el usuario del coche. Por tanto, para el fabricante, este
principio recomendaría dividir la clase motor en otras más
pequeñas que cumplan con las especificaciones de manera
individual.

↑↑↑
Veamos un ejemplo típico de violación
del SRP:
Si una clase tiene dos responsabilidades, entonces asume dos
motivos por los cuales puede ser modificada. Por ejemplo,
supongamos una clase llamada Factura, la cual dentro de un
contexto determinado ofrece un método para calcular el
importe total, tal y como muestra la siguiente figura.

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 3/13
22/03/13 [SRP] Principio de responsabilidad única

Figura 01

↑↑↑
Detectando responsabilidades

La piedra angular de este principio es la identificación de la


responsabilidad real de la clase. Según SRP, una
responsabilidad es "un motivo de cambio"; algo que en
ocasiones es difícil de ver, ya que estamos acostumbrados a
pensar un conjunto de operaciones como una sola
responsabilidad.

Listado 01

class Factura
{
public string Codigo { get; set; }
public DateTime FechaEmision { get; set; }
public decimal ImporteFactura { get; set; }
public decimal ImporteIVA { get; set; }
public decimal ImporteDeduccion { get; set; }
public decimal ImporteTotal { get; set; }
public decimal PorcentajeDeduccion { get; set; }

// Método que calcula el total de la factura


public void CalcularTotal()
{
// Calculamos la deducción
ImporteDeduccion = (ImporteFactura * PorcentajeDeduccion) / 100;
// Calculamos el IVA

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 4/13
22/03/13 [SRP] Principio de responsabilidad única
ImporteIVA = ImporteFactura * 0.16m;
// Calculamos el total
ImporteTotal = (ImporteFactura - ImporteDeduccion) + ImporteIVA;
}
}

Si implementamos la clase Factura tal y como se muestra en el


listado 1, podríamos decir que la responsabilidad de esta clase
es la de calcular el total de la factura y que, efectivamente, la
clase cumple con su cometido. Sin embargo, no es cierto que la
clase contenga una única responsabilidad. Si nos fijamos
detenidamente en la implementación del método CalcularTotal,
podremos ver que, además de calcular el importe base de la
factura, se está aplicando sobre el importe a facturar un
descuento o deducción y un 16% de IVA. El problema está en
que si en el futuro tuviéramos que modificar la tasa de IVA, o
bien tuviéramos que aplicar una deducción en base a una tarifa
por cliente, tendríamos que modificar la clase Factura por cada
una de dichas razones; por lo tanto, con el diseño actual las
responsabilidades quedan acopladas entre sí, y la clase
violaría el principio SRP.

↑↑↑
Separando responsabilidades

El primer paso para solucionar este problema es separar las


responsabilidades; para separarlas, primero hay que
identificarlas. Enumeremos de nuevo los pasos que realiza el
método CalcularTotal:

Aplica una deducción. En base a la base imponible se


calcula un descuento porcentual.
Aplica la tasa de IVA del 16% en base a la base
imponible.
Calcula el total de la factura, teniendo en cuenta el
descuento y el impuesto.

En este método se identifican tres responsabilidades. Recuerde


que una responsabilidad no es una acción, sino un motivo de
cambio, y por lo tanto se deberían extraer las
responsabilidades de deducción e impuestos en dos clases
específicas para ambas operaciones; estableciendo por un lado

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 5/13
22/03/13 [SRP] Principio de responsabilidad única

la clase IVA y por otro la clase Deduccion, tal y como se


presenta en el listado 2.

Listado 2

class IvaNormal
{
private const decimal PORCENTAJE_IVA_NORMAL = 0.16m;
public readonly decimal PorcentajeIvaNormal
{
get
{
return PORCENTAJE_IVA_NORMAL;
}
}

public decimal CalcularIVA(decimal importe)


{
return importe * PORCENTAJE_IVA_NORMAL;
}
}

class Deduccion
{
private decimal m_PorcentajeDeduccion;

public Deduccion(decimal porcentaje)


{
m_PorcentajeDeduccion = porcentaje;
}

public decimal CalcularDeduccion(decimal importe)


{
return (importe * m_PorcentajeDeduccion) / 100;
}
}

Ambas clases contienen datos y un método y se


responsabilizan únicamente en calcular el IVA y la deducción,
respectivamente, de un importe. Además, con esta separación
logramos una mayor cohesión y un menor acoplamiento, al
aumentar la granularidad de la solución. La correcta aplicación
del SRP simplifica el código y se traduce en facilidad de
mantenimiento, mayores posibilidades de reutilización de
código y de crear unidades de testeo específicas orientadas a
cada clase/responsabilidad. El listado 3 muestra la nueva
versión de la clase Factura, que hace uso de las dos nuevas
clases IVA y Deducción.

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 6/13
22/03/13 [SRP] Principio de responsabilidad única

Listado 3

class FacturaFactorizada
{
public string Codigo { get; set; }
public DateTime FechaEmision { get; set; }
public decimal ImporteFactura { get; set; }
public decimal ImporteIVA { get; set; }
public decimal ImporteDeduccion { get; set; }
public decimal ImporteTotal { get; set; }
public decimal PorcentajeDeduccion { get; set; }

// Método que calcula el total de la factura


public void CalcularTotal()
{
// Calculamos la deducción
Deduccion deduccion = new Deduccion(PorcentajeDeduccion);
ImporteDeduccion = deduccion.CalcularDeduccion(ImporteFactura);
// Calculamos el IVA
IvaNormal iva = new IvaNormal();
ImporteIVA = iva.CalcularIVA(ImporteFactura);
// Calculamos el total
ImporteTotal = (ImporteFactura - ImporteDeduccion) + ImporteIVA;
}
}

Nota: La correcta aplicación del SRP simplifica el código y se


traduce en facilidad de mantenimiento, mayores posibilidades
de reutilización de código y de crear unidades de testeo
específicas para cada responsabilidad

↑↑↑
Otro Ejemplo

Veamos otro ejemplo típico de violación del SRP: Supongamos


que tenemos la clase Employee [Empleado] en un sistema de
gestión de una empresa cualquiera. Esta clase nos permite
realizar las tareas esperadas sobre un empleado: Cargarlo y
almacenarlo en una base de datos, generar la nómina,
información básica del empleado, etc.

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 7/13
22/03/13 [SRP] Principio de responsabilidad única

Figura 2

Ahora supongamos dos aplicaciones que hacen uso de la clase


Employee. Una para ser usada por el departamento de recursos
humanos [RRHH_System] para la gestión de las nominas del
personal y otra para la gestión de los proyectos que lleva la
empresa.

¿Podemos pensar que no se está siguiendo el SRP? Lo que


sería lo mismo, ¿creemos que la clase Employee tiene más de
una razón por la que pueda cambiar? A mí se me ocurren unas
cuantas: Cambiar el formato de almacenamiento de base de
datos, modificar los campos que definen a un empleado,
cambiar la lógica de generación de nóminas, etc. Es decir, esta
clase tiene varias responsabilidades: Es responsable de la
persistencia de los clientes, responsable de caracterizar a un
empleado, responsable de generar las nóminas, etc.

Las consecuencias de violar el SRP en este caso son dos:

La clase Employee tiene una dependencia con la clase


AccountService para poder realizar el cálculo de las
nóminas. Por tanto la aplicación de gestión de proyectos,
a la hora de hacer el despliegue de esa aplicación,
tambien debe incluir la librería que contiene esa clase
aunque no la necesite.
Si alguna de las aplicaciones necesita implementar nueva
funcionalidad y requiere cambiar la definición de la clase
Employee, este cambio arrastraría cambios en el resto de
aplicaciones que requerirían adaptarse a los nuevos
cambios de la clase. En caso de olvidarnos, las
consecuencias serían impredecibles.
jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 8/13
22/03/13 [SRP] Principio de responsabilidad única

Una mejora en el diseño sería separar las responsabilidades en


clases distintas

Figura 3

Hemos creado dos nuevas clases: una para la gestión de


nóminas y otra para el almacenamiento en la base de datos.
Hay que fijarse en el detalle de que la clase Employee no
depende de las nuevas clases EmployeeAccount y de
EmployeeStorage, sino que la dependencia la tienen las
aplicaciones.

↑↑↑
Una forma de probar este principio

Una forma para probar este principio es escribir en un papel


algo parecido a la siguiente imagen, en la primera línea se
escribe el nombre de la clase, en las siguientes líneas

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabili… 9/13
22/03/13 [SRP] Principio de responsabilidad única

escribiremos el nombre de la clase y los métodos de las clase,


ocuparemos tantas líneas como métodos tengamos en la clase,
luego leeremos cada línea y analizaremos si la frase tiene
sentido y si la clase tiene la responsabilidad del método
descrito.

Figure 04

Veamos un ejemplo con la siguiente clase:

Figura 5

Veamos el resultado de aplicar el análisis en base al


documento que se definió.

Figura 6

Aclarando que el método obtenerAceite() se refiere solo a una


lectura de aceite ó con una posibilidad de asignar esta
jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabi… 10/13
22/03/13 [SRP] Principio de responsabilidad única

responsabilidad a otra clase.

↑↑↑
Ampliando el abanico de
"responsabilidades"
Comentábamos anteriormente que no es fácil detectar las
responsabilidades, ya que generalmente tendemos a
agruparlas. No obstante, existen escenarios o casuísticas en
los que "se permite" una cierta flexibilidad. Robert C. Martin
expone un ejemplo utilizando la interfaz Modem:

Listado 4

interface Modem
{
void dial(int pNumber);
void hangup();
void send(char[] data);
char[] receive();
}

En este ejemplo se detectan dos responsabilidades,


relacionadas con la gestión de la comunicación (dial y hangup)
y la comunicación de datos (send y receive). Efectivamente,
cada una de las funciones puede cambiar por diferentes
motivos; sin embargo, ambas funciones se llamarán desde
distintos puntos de la aplicación y no existe una dependencia
entre ellas, con lo que no perderíamos la cohesión del sistema.

↑↑↑
Conclusión
Pensemos siempre en el ciclo de vida de una aplicación, y no
únicamente en su diseño y desarrollo. Toda aplicación sufre
modificaciones a causa de cambios en los requisitos o arreglo
de fallos existentes, y el equipo de desarrollo puede variar; si
a ello le sumamos que el código es difícil de mantener, los
costes de mantenimiento se dispararán, y cualquier
modificación se presentará como una causa potencial de

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabi… 11/13
22/03/13 [SRP] Principio de responsabilidad única

errores en entidades relacionadas dentro del sistema.

En definitiva. Este principio es uno de los más simples de


SOLID, y sin embargo de los más difíciles de implementar
correctamente. Aplicando SRP, podemos alcanzar niveles más
bajos de acoplamiento y una cohesión más alta del sistema.

↑↑↑
Referencia Bibliográfica

Principio de responsabilidad única. José Miguel Torres


http://www.desarrolloweb.com/manuales/programacion-
orientada-objetos-dotnet.html
http://www.desarrolloweb.com/articulos/principio-
reponsabilidad-unica-I-dotnet.html
http://www.desarrolloweb.com/articulos/principio-
reponsabilidad-unica-II-dotnet.html
The Art of the Left Foot. El blog de Oscar Arrivi sábado,
29 de mayo de 2010, S.O.L.I.D. Principios de Diseños
Orientados a Objeto (parte 1)
http://theartoftheleftfoot.blogspot.com.es/2010/05/solid-
principios-de-disenos-orientados.html
Wikipedia
http://en.wikipedia.org/wiki/Single_responsibility_principle
Miguel Rugerio
http://desasoftware.blogspot.com.es/2010/05/responsabilidad-
unica.html

↑↑↑
A.2.Enlaces

[Para saber mas]

[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]
¡ No Olvides ñadir éste sitio a tus marcadores favoritos !
Pulsa (Ctrl + D)

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabi… 12/13
22/03/13 [SRP] Principio de responsabilidad única

© 1997 - 2013 - La Güeb de Joaquín


Joaquín Medina Serrano [ Mail ] [ Web ]
Ésta página es española

Codificación UTF-8
Fecha de creación No existe una fecha
Última actualización 2013-03-23T09:29:00Z

jms32.eresmas.net/web2008/documentos/informatica/documentacion/logica/OOP/Principios/Oop_Solid_SRP/2012_09_04_SOLID_SRP_PrincipioResponsabi… 13/13

Вам также может понравиться