El Principio de sustitución de Liskov básicamente no le permite usar en exceso la herencia de implementación: ¡nunca debe usar la herencia solo para la reutilización de código (hay composición para esto)! Al adherirse a LSP, puede estar bastante seguro de que realmente existe una "relación es-es" entre su superclase y su subclase.
Lo que dice es que sus subclases deben implementar todos los métodos de la subclase de manera similar a la implementación de los métodos en la subclase. Nunca debe anular un método con la implementación de NOP o devolver nulo cuando el supertipo arroja una excepción; indicado en los términos de Diseño por Contrato, debe respetar el contrato del método de la superclase al anular un método. Una forma de defenderse contra la ruptura de este principio es nunca anular un método implementado; en su lugar, extraiga una interfaz e implemente esa interfaz en ambas clases.
Principio de segregación de interfaz , Principio de responsabilidad única y Principio de alta cohesión de GRASP están de alguna manera relacionados; se refieren al hecho de que una entidad debe ser responsable de una sola cosa para que haya una sola razón para el cambio y que el cambio se realice con mucha facilidad.
En realidad dice que si una clase implementa una interfaz, entonces debe implementar y usar todos los métodos de esa interfaz. Si hay métodos que no son necesarios en esa clase en particular, entonces la interfaz no es buena y debe dividirse en dos interfaces, una que solo tenga los métodos necesarios para la clase original. Se puede considerar desde un POV, que se relaciona con el principio anterior por el hecho de que no le permite crear interfaces grandes para que su implementación pueda romper el LSP.
Puede ver la Inversión de dependencias en el Patrón de fábrica; aquí, tanto el componente de alto nivel (el cliente) como el componente de bajo nivel (instancia individual que se creará) dependen de la abstracción(La interfaz). Una forma de aplicarlo en una arquitectura en capas: no debe definir una interfaz para una capa en la capa que se implementa sino en el módulo que se llama. Por ejemplo, la API de la capa de origen de datos no debe escribirse en la capa de origen de datos sino en la capa de lógica de negocios, donde es necesario llamarla. De esta manera, la capa de origen de datos hereda / depende del comportamiento definido en la lógica de negocios (por lo tanto, la inversión) y no al revés (como sería de una manera normal). Esto proporciona flexibilidad en el diseño, permitiendo que la lógica de negocios funcione sin ningún cambio de código, con otra fuente de datos completamente diferente.