A continuación se muestra un sencillo ejemplo en C# del principio LSP. Se pretende implementar una pequeña jerarquía de clases para guardar mensajes de log bien a un fichero de texto bien a una base de datos.

En una primera aproximación, podríamos pensar en algo así:

public class BasicMessage { string _msg; DateTime _dateTime; public string Msg { set { _msg = value; _dateTime = DateTime.Now; } get { return _msg; } } public string FormatMessage() { return string.Format("Set time at: {0} - Message: {1}", _dateTime, _msg); } } class TextLogMessage : BasicMessage { public void WriteMessageToLog() { //... } } class DataBaseLogMessage : BasicMessage { public void WriteMessageToDataBase() { //... } }

De este modo, si tenemos una función que quiera escribir los mensajes iniciales al comenzar la ejecución de la aplicación al fichero de texto, tendría el siguiente prototipo:

void writeInitialLogs( TextLogMessage msg ) { log.Msg = "Application up&running"; log.WriteMessageToLog(); }

Y si se quisiera guardar en su lugar los mensajes en la base de datos, la función debería ser así:

void writeInitialLogs( DataBaseLogMessage msg ) { log.Msg = "Application up&running"; log.WriteMessageToDataBase(); }

Pero..., esta jerarquía de ejemplo viola LSP, porque en nuestro código cliente (la función writeInitialLogs), no se puede usar indistintamente como parámetro TextLogMessage o DataBaseLogMessage, que son las clases hijas de BasicMessage. De este modo estamos implementando las writeInitialLogs() con rigidez, ligado a una solución concreta en la forma de guardar el mensaje de log.

Una versión correcta de esta jerarquía que cumpliría LSP sería la siguiente:

public class BasicMessage { string _msg; DateTime _dateTime; public string Msg { set { _msg = value; _dateTime = DateTime.Now; } get { return _msg; } } public string FormatMessage() { return string.Format("Set time at: {0} - Message: {1}", _dateTime, _msg); } public virtual void WriteMessage() { } } class TextLogMessage : BasicMessage { public override void WriteMessage() { //... } } class DataBaseLogMessage : BasicMessage { public override void WriteMessage() { //... } }

De este modo, la función writeInitialLogs() se podría reescribir como

void writeInitialLogs( BasicMessage msg ) { log.Msg = "Application up&running"; log.WriteMessage(); }

Y se invocaría como

writeInitialLogs( new TextLogMessage() );

O bien

writeInitialLogs( new DataBaseLogMessage() );

De este modo:

  • La función writeInitialLogs() queda desacoplada de una implementación concreta de BasicMessage.
  • Se cumple el principio LSP ya que writeInitialLogs() puede usar indistintamente todas las clases hija de BasicMessage y su funcionamiento será válido.
  • Se cumple además OCP, ya que hemos diseñado BasicMessage abierto para la extensión pero cerrada a las modificaciones.
  • Lo dejamos todo listo y preparado para el principio de inversión de dependencias o DIP, ya que la instancia del objeto que recibe writeInitialLogs() como parámetro se puede establecer como un mecanismo general a la aplicación.

¿Por qué leer El Libro Negro del Programador?

Adquirir desde:
Amazon (kindle eBook / papel)
CreateSpace (papel)
PayHip (epub / mobi / pdf)

El libro negro del programador.com
Segunda Edición - 2017

El libro negro del programador.com
Now available in english!

Archivo

Trabajo en...

Mis novelas...