jueves, 17 de marzo de 2011

Principio de responsabilidad única (II)

Continuamos con el Principio de Responsabilidad Única, una de las bases de la programación oriendada a objetos.

Continuando con el artículos anterior sobre el principio de resposabilidad única dentro del manual sobre los principios fundamentales de la Programación Orientada a Objetos, pasamos a ver:

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.

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.

Listado 1
public class Factura
{
public string _codigo;
public DateTime _fechaEmision;
public decimal _importeFactura;
public decimal _importeIVA;
public decimal _importeDeduccion;
public decimal _importeTotal;
public ushort _porcentajeDeduccion;
// Método que calcula el total de la factura
public void CalcularTotal()
{
// Calculamos la deducción
_importeDeduccion = (_importeFactura * _porcentajeDeduccion) / 100;
// Calculamos el IVA
_importeIVA = _importeFactura * 0.16m;
// Calculamos el total
_importeTotal = (_importeFactura - _importeDeduccion) + _importeIVA;
}
}

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 CalcularTotal1:
  • 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 la clase IVA y por otro la clase Deduccion, tal y como se presenta en el listado 2.

Listado 2
public class IVA
{
public readonly decimal _iva = 0.16m;
public decimal CalcularIVA(decimal importe)
{
return importe * _iva;
}
}
public class Deduccion
{
private decimal _deduccion;
public Deduccion(ushort porcentaje)
{
_deduccion = porcentaje;
}
public decimal CalcularDeduccion(decimal importe)
{
return (importe * _deduccion) / 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 Deduccion.

Listado 3
public class Factura
{
public string _codigo;
public DateTime _fechaEmision;
public decimal _importeFactura;
public decimal _importeIVA;
public decimal _importeDeduccion;
public decimal _importeTotal;
public ushort _porcentajeDeduccion;
// 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
IVA iva = new IVA();
_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

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:

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 poco mantenible, los costes de mantenimiento se dispararán, y cualquier modificación se presentará como una causa potencial de errores en entidades relacionadas dentro del sistema.
Para Comentar Elige el Sistema de Comentario de tu Agrado:
comentarios google
comentarios blogger
comentarios facebook

Comparte este post con tus amigos!

...o también puedes seguir el blog en:

No olvides suscribirte, para recibir todas mis actualizaciones, directamente a tu email.

Ingresa tu correo electrónico:

Recuerda confirmar tu suscripción, haciendo click en el enlace que recibirás por email.

0 comentarios:

Comparte tu opinión con los demás, deja un comentario. ↓

Los comentarios son moderados, si contienen insultos o son ofensivos no se publicaran.

Es muy importante saber tu opinion sobre lo que se publica en este blog asi que POR FAVOR DEJA TU COMENTARIO.

Comentar es facil, simplemente escribe tu comentario en el cuadro de abajo, trata de comentar con tu perfil abilitado o donde dice Comentar como: selecciona Nombre/URL escribes tu nombre y listo!! (URL puede dejarse en blanco)

:a   :b   :c   :d   :e   :f   :g   :h   :i   :j   :k   :l   :m   :n   :o   :p   :q   :r   :s   :t Add smileys to Blogger +

 

©2009 - 2013 Pichujitos | Theme diseñado por chicoloco123 para Fuutec.com | Ir arriba ↑