Este es el tercer principio de los principios de programación SOLID y se relaciona con una característica de la programación orientada a objetos: la Herencia.
Significado
El principio Declara que una subclase debe ser sustituible por su superclase.
Si en nuestro programa al hacer esto la aplicación falla, estaremos incumpliendo este principio SOLID.
Cumpliendo con este principio se confirmará que nuestro programa tiene una jerarquía de clases fácil de entender y un código reutilizable.
Ejemplo
Siguiendo con los ejemplos de los artículos de Principio de responsabilidad única y el Principio de abierto/cerrado imaginemos que queremos controlar si una persona puede acceder a una sala restringida sólo a ciertos trabajadores. En nuestro ejemplo tendremos operarios, técnicos, estudiantes, jefes y guardias y sólo los guardias y los jefes podrán acceder a la sala de control ya que estas dos clases incluyen la función entraEnSalaDeControl(). Realizaremos esta gestión en la clase ControlarAcceso que contiene una función para imprimir si tiene acceso o no a la sala.
A esta función se le pasa como parámetro(array) una lista de objetos de la clase Persona.
Veamos el código.
class Persona {
propiedad nombre
propiedad apellidos
propiedad nacionalidad
propiedad fechaDeNacimiento
funcion calculaEdad()
}
class Operario: Persona {
propiedad numeroDeIdentificación
funcion utilizaHerramienta()
funcion tomaUnDescanso()
}
class Técnico: Persona {
propiedad numeroDeIdentificación
funcion utilizaHerramienta()
funcion revisaOperario()
funcion controlaCalidad()
funcion tomaUnDescanso()
}
class Jefe: Persona {
propiedad departamento
funcion revisaPersona()
funcion controlaCalidad()
funcion entraEnSalaDeControl() {
imprime(“Jefe.nombre accede a la sala de control»)
}
}
class Guardia: Persona {
propiedad numeroDePlaca
funcion vigilaSala()
funcion arrestaPersona()
funcion entraEnSalaDeControl() {
imprime(“Guardia.nombre accede a la sala de control»)
}
}
class ControlarAcceso {
funcion imprimePermisos(listaDePersonas: Array de Persona) {
Bucle personaDeLaLista en listaDePersonas {
Si personaDeLaLista esInstanciaDe Operario
ENTONCES imprime(“personaDeLaLista.nombre no tiene acceso.»)
Si personaDeLaLista esInstanciaDe Técnico
ENTONCES imprime(“personaDeLaLista.nombre no tiene acceso.»)
Si personaDeLaLista esInstanciaDe Guardia
ENTONCES personaDeLaLista.entraEnSalaDeControl()
Si personaDeLaLista esInstanciaDe Jefe
ENTONCES personaDeLaLista.entraEnSalaDeControl()
}
}
}
Este código además de incumplir el principio de abierto / cerrado incumple el principio de substitución de Liskov.
Solución
Utilizando las propiedades de la Herencia en programación orientada a objetos podemos incluir una función entraEnSalaDeControl() con un valor por defecto de no acceso en la clase Persona.
Todas las clases hijas heredarán esta función por lo que sólo habría que sobreescribir esta función en las clases que si tengan acceso.
El código quedaría de la siguiente forma.
class Persona {
propiedad nombre
propiedad apellidos
propiedad nacionalidad
propiedad fechaDeNacimiento
funcion calculaEdad()
funcion entraEnSalaDeControl() {
imprime(“Persona.nombre no tiene acceso a la sala de control»)
}
}
class Operario: Persona {
propiedad numeroDeIdentificación
funcion utilizaHerramienta()
funcion tomaUnDescanso()
}
class Técnico: Persona {
propiedad numeroDeIdentificación
funcion utilizaHerramienta()
funcion revisaOperario()
funcion controlaCalidad()
funcion tomaUnDescanso()
}
class Jefe: Persona {
propiedad departamento
funcion revisaPersona()
funcion controlaCalidad()
SobreEscrito funcion entraEnSalaDeControl() {
imprime(“Persona.nombre accede a la sala de control»)
}
}
class Guardia: Persona {
propiedad numeroDePlaca
funcion vigilaSala()
funcion arrestaPersona()
SobreEscribe funcion entraEnSalaDeControl() {
imprime(“Persona.nombre accede a la sala de control»)
}
}
class ControlarAcceso {
funcion imprimePermisos(listaDePersonas: Array de Persona) {
Bucle personaDeLaLista en listaDePersonas {
personaDeLaLista.entraEnSalaDeControl
}
}
}
Ahora la función imprimePermisos no tiene que consultar a qué clase pertenece la persona de la lista ya que por contrato de herencia todas las clases hijas de Persona incluyen la función entraEnSalaDeControl(). Esto facilita que si en el futuro es necesario agregar nuevas clases hijas de Persona sólo habrá que sobreescribir la función en aquellas clases que si tengan acceso. De esta forma mejoramos el mantenimiento del proyecto.