Principios básicos del diseño de software

Principios básicos del diseño de software

Principios básicos del diseño de software (SOLID)

En este post vamos a hablar de algo tan importante como son algunos de los principios del diseño del software. Este tema no es algo nuevo, sin embargo, es importante recordar algunos de esos principios. Existen muchos principios de diseño comúnmente aceptados, pero en este post solo abordaremos los principios SOLID.

¿Por qué usar estos principios?

Todo desarrollo, antes o después, se ve sometido a cambios sobre la funcionalidad inicial o simplemente se requiere funcionalidad nueva.
Estos principios nos proporcionan unas bases para la construcción de aplicaciones mucho más sólidas y robustas. Permiten que los cambios y la evolución del software tenga un mínimo impacto en el código ya desarrollado tratando de evitar que lo que funciona deje de funcionar y por ello que el coste del mantenimiento sea mucho menor.
A continuación pasamos a ver SOLID que es un acrónimo de 5 principios básicos en el diseño y programación orientada a objetos.

Single responsibility (Principio de responsabilidad única)

Este principio dice que cada clase tiene que tener una responsabilidad única y concreta, como dice Rober C. Martín “Una clase debería tener una y sólo una razón para cambiar”.
Es común que cuando empezamos a desarrollar se acabe tomando decisiones como meter en una clase un método a causa de que esa clase lo utiliza, el problema llega cuando más adelante ese método lo necesitamos usar en otras clases y vemos que pierde coherencia.
Supongamos que tenemos que realizar una aplicación para registrar las ofertas presentadas y las ventas cerradas. Se puede crear una clase vendedor con un método “GenerarOferta” que registrará las ofertas presentadas y otro “CerrarVenta” que registrará las ofertas ganadas.

 

Diseño de software

A priori, el ejemplo, pude parecer correcto, pero en realidad estamos mezclando 2 conceptos (oferta y venta). La forma en que se realiza una oferta puede variar por diversos motivos, lo mismo ocurre con el procedimiento de venta que también puede cambiar, lo cual implicará modificar la clase por 2 motivos diferentes.

 

2

Después de hacer las modificaciones, vemos que si ahora cambia la forma de realizar una oferta no impacta sobre la venta y si cambia la forma de cerrar la venta no impacta sobre la oferta.

Open-Close (Principio de abierto-cerrado)

Lo que dice este principio es que no se debe modificar el código de una clase o entidad, sino que estas deben de ser extendidas y para que esto se cumpla, nuestro código debe estar bien diseñado. La forma más común para cumplir con este principio es el uso de la herencia y/o el de las interfaces. Cumplir el principio de responsabilidad única ayuda a que este otro principio también se cumpla, pero no significa que cumpliendo uno se cumpla el otro.

Sigamos con el ejemplo anterior, supongamos ahora que vamos a realizar la oferta y que dependiendo del tipo de servicio tendremos que generar una estructura diferente en cada caso. Añadiremos una propiedad de tipo enumerado en la clase Oferta que nos indique el tipo de servicio y un método por cada servicio que genere una estructura u otra, cuando realicemos la oferta tendremos que comprobar el tipo y en función de este llamar a uno u otro método.

Diseño de software

En este ejemplo, si queremos ofrecer un nuevo servicio nos vemos obligados a modificar la clase Oferta y el método “RealizarOferta”, por lo que estamos incumpliendo el principio abierto-cerrado. En el siguiente ejemplo mostramos como se podría solucionar.

Diseño de software

Como podemos ver en el ejemplo, al crear por cada tipo del enumerado una clase que herede de Oferta e implemente su método “GenerarOferta”, conseguimos simplificar la funcionalidad de forma que no sea necesario realizar modificaciones si añadimos un nuevo servicio, ya que bastará con crear una nueva clase que herede de Oferta e implemente el método. En el siguiente ejemplo añadimos el servicio de consultoría.

Diseño de software

Liskov Substitution (Principio de Sustitución de Liskov)

Este principio recibe su nombre por su creadora Barbara Liskov. Viene a decir que una clase derivada de otra debe poder ser sustituida por su clase base y debemos garantizar que los métodos de la primera no provoquen un mal funcionamiento de los métodos de la clase base.

Vamos a utilizar un ejemplo muy recurrido para explicar este principio, el del cuadrado y el rectángulo. Un cuadro no es más que un rectángulo con todos los lados iguales, intentemos llevar esto a la programación y calcular su área.
Diseño de software

Hemos creado una clase “Rectángulo” con unos métodos para obtener ancho y alto, otros para modificar el ancho y el alto, y un método que calcula el área. Hemos creado también una clase “Cuadrado” que hereda de “Rectángulo” y sobrescribe los métodos que cambian el ancho y alto para que mantengan una relación.

7

El siguiente método lo usamos para testear nuestras clases. Si nos fijamos siempre que se pase un rectángulo funcionará correctamente, pero si cambiamos el rectángulo por el cuadrado no funcionará y por ello incumple el principio de Liskov.

Diseño de software

Como se puede ver, hemos cambiado las clases para que sus constructores reciban ancho y alto por parámetros, el lado en caso del cuadrado. De esta forma estamos obligando en la definición del objeto a indicar el valor que tendrán sus lados, haciendo su uso más intuitivo y evitando que haya operaciones por detrás que nos lleven a confusión.

Interface Segregation (Principio de Segregación de Interfaces)

Mejor crear muchas interfaces que contengan pocos métodos, que crear pocas interfaces que definan demasiados métodos. El motivo de este principio es que ninguna clase debe de estar obligada a implementar métodos que no necesita, por ello es preferible crear varias interfaces que agrupen funcionalidad común, a englobar gran parte de esa funcionalidad en unas pocas interfaces y encontrarnos más adelante que necesitamos implementar una interface que nos obliga a implementar métodos que no necesitamos.

En el siguiente ejemplo volvemos a nuestro proyecto de las ofertas.

Diseño de software

Esta vez, tendremos una interface “IOferta” que define una serie de métodos que se usan en las ofertas. Si nos fijamos, cuanto heredamos de esa interface en la clase “Proyecto” nos vemos obligados a implementar el método “EstablecerDesplazamiento”, que nos viene bien para el outsourcing, pero en proyectos que se van a desarrollar internamente no lo necesitamos y si lo usamos devolverá una excepción.

Diseño de software

Lo que hemos hecho para solucionarlo es crear una nueva interface que defina el método “EstablecerDesplazamiento” e implementarla solo donde se necesita. Ahora no tenemos métodos implementados que no necesitamos usar.

Dependency Inversion (Principio de Inversión de Dependencia)

Este principio busca que no existan un alto acoplamiento en las aplicaciones, ya que ello repercute en un difícil mantenimiento.

El principio quiere decir que las clases de alto nivel no tienen que depender de otras de bajo nivel, sino que ambas dependan de abstracciones, así como que las abstracciones no deben depender de los detalles, sino al contrario.

Imaginemos que tenemos que generar una oferta y que dependiendo del su tipo se generará con una estructura u otra.

Diseño de software

En este ejemplo disponemos de un método principal que recibe una oferta y en base al tipo de esta decidimos se guarda en Word o en PDF. El problema que encontramos es que hay un fuerte acoplamiento y dependencias entre las clases. Si más adelante se requiere que una oferta concreta se guarde en ambos formatos, nos vemos obligados a cambiar toda la lógica del método.

Diseño de software

Para solucionar el problema se ha creado una Interface con la definición del método para guardar y que implementarán los diferentes tipos de documento, finalmente se ha añadido como parámetro al método principal la Interface. Con estos cambios podemos ver que ahora no dependemos del tipo de oferta, sino que hemos invertido la dependencia, será el método que llame a este el responsable de indicar el tipo de documento.

Artículo escrito por Luis Miguel Rodríguez González programador en MVP CLUSTER

Fuentes:

Principios SOLID en la programación orientada a objetos: SOLID, Blog de Chema: http://jmperezramos.net/programacion/principios-solid-en-la-programacion-orientada-a-objetos/

Los 5 Principios Fundamentales de la Orientación a Objetos, Adrián M. Paredes: http://elblogdelfrasco.blogspot.com.es/2012/03/solid-los-5-principios-fundamentales-de.html

Solid, cinco principios básicos de diseño de clases, Jorge Rubira: https://www.genbetadev.com/paradigmas-de-programacion/solid-cinco-principios-basicos-de-diseno-de-clases

Los principios SOLID para diseño de objetos, Leonardo De Seta: https://dosideas.com/noticias/desarrollo-de-software/968-los-principios-solid-para-diseno-de-objetos

Introducción a los Principios SOLID, Raúl Expósito: http://raulexposito.com/documentos/solid/

Principio de responsabilidad única (SOLID 1ª parte), Antonio Leiva: https://devexperto.com/principio-responsabilidad-unica/

Principio Open/Closed (SOLID 2ª parte), Antonio Leiva: https://devexperto.com/principio-open-closed/

Principio de sustitución de Liskov (SOLID 3ª parte), Antonio Leiva: https://devexperto.com/principio-de-sustitucion-de-liskov/

Principio de Segregación de Interfaces (SOLID 4ª parte), Antonio Leiva: https://devexperto.com/principio-de-segregacion-de-interfaces/

Principio de Inversión de Dependencias (SOLID 5ª parte), Antonio Leiva: https://devexperto.com/principio-de-inversion-de-dependencias/

Principios SOLID, DotNet Desarrollo de Sistemas, Victor Salazar: https://youtu.be/hnsGhTUxIew

No hay comentarios

Dejar un comentario

Comentario
Nombre
Email
Sitio Web