Principios de
Diseño Orientado
a Objetos
PRINCIPIOS DE DISEÑO DE CLASES
• PRINCIPIO ABIERTO-CERRADO (OCP): Un
módulo debe ser abierto para extensión pero
cerrado para modificación.
• Wikipidia: La noción de que las “entidades de
software … deben estar abiertas para su
extensión, pero cerradas para su
modificación”.
• Principio Abierto-Cerrado: Abierto a
extensiones Cerrado a modificaciones de
código existente debido a extensiones
PRINCIPIOS DE DISEÑO DE CLASES
• El Principio Open/Closed (Open/Closed Principle, OCP) fue acuñado por el Dr. Bertrand Meyer en su libro "Object Oriented Software
Construction" y básicamente lo que nos dice este principio es que "las entidades de software (clases, módulos, funciones…) deben estar
abiertas para extenderse, pero cerradas para modificación". • Las clases que cumplen con OCP tienen dos características:
– Son abiertas para la extensión; es decir, que la lógica o el comportamiento de esas clases puede ser extendida en nuevas clases, usando herencia. – Son cerradas para la modificación, y por tanto el código fuente de dichas
clases debería permanecer inalterado.
• ¿Qué significa esto?: Que una entidad tiene que ser extendida sin necesidad de ser modificada internamente. Por ejemplo, deberíamos poder ampliar la funcionalidad de una clase vía herencia sin necesidad de tener que modificar su comportamiento interno.
Principio abierto/cerrado
Las entidades software deben estar abiertas para su extensión, pero cerradas para su modificación
Bertran Meyer
Diseño cerrado/cerrado
• Finalidad
– Sistema funcionando (cerrado), pero ampliable (abierto)
– Conseguir cambios añadiendo nuevo código sin afectar al resto de elementos del diseño
• Ambigüedad
– La dependencia “uno a uno” se transforma en una dependencia de “uno a muchos”
• Ventajas
• Evita que cambios en un módulo afecten a otros módulos
Diseño abierto/cerrado
Principio abierto/cerrado
Análisis
Diseño cerrado/cerrado Clase A Clase B
Clase A Clase Abstracta B
Principio de responsabilidad única
Principio de Única Responsabilidad (Single responsibility principle)La noción de que un objeto solo debería tener una
única responsabilidad
• El Principio de responsabilidad única (Single Responsability Principle - SRP) fue acuñado por Robert C. Martin en un artículo del mismo título y popularizado a través de su conocido libro [patrones Gof]
• "Cada objeto en el sistema deben tener una simple responsabilidad, y todos los servicios de los objetos deben cumplir con esa simple responsabilidad" • En términos prácticos, este principio establece que:
• "Una clase debe tener una y solo una única causa por la cual puede ser modificada.“
Principio de responsabilidad única
Principio de Única Responsabilidad (Single responsibility principle)La noción de que un objeto solo debería tener una
única responsabilidad
Diseño con una sola clase (incorrecto)
Cliente P Cliente Q Clase X Elementos asociados a la responsabilidad A Elementos asociados a la responsabilidad B • Finalidad
– Evitar que el cambio de una
responsabilidad en una clase pueda provocar fallos en las demás
responsabilidades de la clase
– Evitar que los clientes de una clase carguen con elementos que no utilizan
Diseño con una sola clase (no adecuado)
Diseño con dos clases
Cliente P Cliente Q Clase X Elementos asociados a la responsabilidad A Elementos asociados a la responsabilidad B Cliente P Cliente Q Clase XA Elementos asociados a la responsabilidad A Clase XB Elementos asociados a la responsabilidad B
Principio de responsabilidad única
Principio de responsabilidad única
Justificación del principio según R. Martin
Principio de cohesión (DeMarco y Pages-Jones)
Cohesión: Relación funcional de los elementos de un módulo
Cohesión = responsabilidad única (Martin)
Principio de responsabilidad única (Martin) Responsabilidad: razón de cambio
Principio de responsabilidad única
¿ cohesión = razón de cambio ?
• Creencia
– Alta cohesión y bajo acoplamiento conlleva facilidad de modificación
• Problema (
incluye lo que estaba escrito antes)
– Infinitud de definiciones de cohesión y acoplamiento
• Consecuencia
– No hay justificación para asociar cohesión con fuerzas de cambio
Diseño con una clase
• Realidad del principio:
– División salomónica puntual • Ambigüedad:
– Aumenta entre los elementos de responsabilidades separadas
– Aumenta entre la clase cliente hacia las clases separadas que no utilizan
– Disminuye entre la clase cliente hacia las clases separadas que utilizan
Cliente P Cliente Q
Clase X
Responsabilidad A Responsabilidad B
Diseño con dos clases Cliente P Cliente Q Clase XA Responsabilidad A Clase XB Responsabilidad B
Principio de responsabilidad única
Principio de inversión de dependencias
Los módulos de alto nivel no deben depender de los módulos de bajo nivel. Ambos deben depender de las abstracciones
Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.
Principio de inversión de dependencias
• Básicamente lo que nos dice este principio es que
– Las clases de alto nivel no deberían depender de las clases de bajo nivel. Ambas deberían depender de las abstracciones.
– Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones.
• El Principio de Inversión de dependencia ayuda a mantener nuestro código totalmente desacoplado,
asegurándonos que dependemos de abstracciones en vez de implementaciones concretas. La Inyección de
dependencias es una implementación de este principio, aunque ambos términos se usan de forma intercambiable.
Principio de inversión de dependencias
• Finalidad:
– Conseguir que los cambios en los módulos de bajo nivel no afecten a los módulos de alto nivel
– Facilitar la reutilización de los módulos de alto nivel
Diseño tradicional
Nivel Política
Nivel Mecanismo
Diseño tradicional
Nivel Política
Nivel Mecanismo
Nivel Utilidad
Principio de inversión de dependencias
Diseño con inversión de dependencias
Nivel Política Nivel Mecanismo Nivel Utilidad Interfaz Política Interfaz Mecanismo Política Mecanismo Utilidad
Principio de separación de la interfaz
Los clientes no deben ser forzados a depender de interfaces que no utilizan
Robert C. Martin
• Básicamente lo que nos quiere decir este principio es que las clases que implementen una interfaz o una clase abstracta no deberían estar obligadas a tener partes que no van a utilizar. • Una interfaz es un contrato que debe cumplir una clase, y tales
contratos deben ser específicos, no genéricos; esto nos proporcionará una forma más ágil de definir una única
responsabilidad por interfaz - de otra forma, violaríamos además el Principio de Responsabilidad Única
Principio de separación de la interfaz
Los clientes no deben ser forzados a depender de interfaces que no utilizan
Robert C. Martin
• Otras definiciones de este principio son:
• La implementación de las abstracciones debe estar en la medida de lo posible en interfaces y no en clases.
• Los clientes no deben estar obligados a implementar y/o a depender de una interface que luego no usarán.
• Es mejor tener interfaces específicos para cada cliente que uno de propósito general, o lo que es lo mismo, no
deberíamos obligar a los clientes a depender de métodos que no utilizan.
Diseño con una interfaz (incorrecto)
Diseño con dos interfaces
Cliente C
Cliente D
Interfaz Z
Métodos que utiliza el cliente C
Métodos que utiliza el cliente D
Cliente C
Cliente D
interfaz ZC
Métodos que utiliza el cliente C
Interfaz ZD
Métodos que utiliza el cliente D
Diseño con una interfaz
• Extensión del principio de responsabilidad única
• Ambigüedad
– Aumenta entre los métodos de interfaces separadas
– Aumenta entre la clase cliente hacia los métodos de las interfaces no utiliza
Cliente C Cliente D
Interfaz Z
Métodos cliente C Métodos cliente D
Diseño con dos interfaces Cliente C Cliente D Interfaz ZC Métodos cliente C Interfaz ZD Métodos cliente D
Principio de separación de la interfaz
Principio de sustitución de Liskov
Los subtipos deben ser sustituibles por sus supertipos
Robert C. Martin
• Básicamente lo que nos dice este principio es que “Cada clase
que hereda de otra puede usarse como su padre sin necesidad de conocer las diferencias entre ellas”
• El Principio de Sustitución de Liskov fue acuñado por Bárbara Liskov (de ahí el nombre del principio) en el año 1987 durante una conferencia sobre Jerarquía y Abstracción de datos.
Principio de sustitución de Liskov
Los subtipos deben ser sustituibles por sus supertipos
Robert C. Martin
• Su principal cometido es la de asegurar en la herencia entre clases de la Programación Orientada a Objetos que una clase derivada debe comportarse como la clase base. La definición es:
• “Debe ser posible utilizar cualquier objeto instancia de una
subclase en lugar de cualquier objeto instancia de su superclase sin que la semántica del programa escrito en los términos de la superclase se vea afectado”
Principio de sustitución de Liskov
Otras definiciones de este principio son:• Cada clase que hereda de otra puede usarse como su padre sin necesidad de conocer las diferencias entre ellas
• Toda subclase debe soportar ser sustituida por su clase base lo que en términos de contratos significa que las precondiciones de los métodos de la subclase no serán más fuertes que las de la clase base, y sus pos condiciones no serán más débiles, es decir, los métodos derivados no deben esperar más ni proveer menos que los
originales.
• Las funciones que usan punteros o referencias a clases base deben ser capaces de utilizar objetos de las clases derivadas sin tener conocimiento de ello (Martin96b), también: “Las clases derivadas deben ser utilizables a través de la interfaz de la clase base, sin necesidad de que el usuario conozca la diferencia”
• Si por cada objeto O1 del tipo S existe un objeto O2 del tipo T tal que para todos los programas P definidos en términos de T y el comportamiento de P permanece
Rectángulo Cuadrado Propiedades alto ancho lado Operaciones SetAlto(x) SetAncho(y) GetAlto() GetAncho() SetLado(z) GetLado() Rectángulo Cuadrado ES – UN ?
Principio de sustitución de Liskov
¿ Rectángulo ES-UN Cuadrado ?
• Ambigüedad:
– Los programas no saben si
trabajan con objetos de supertipos o de subtipos
• Ventajas
• El enunciado de Martin es confuso:
– “Los subtipos deben ser sustituibles
por los supertipos”, pero la definición
de subtipo se basa en la sustitución
S es subtipo de T
Obj-1 es un objeto de S
Obj-2 es un objeto de T
Para todo programa P ( T )
comportamiento P(Obj-1) = comportamiento P(Obj-2) Cuando Obj-1 es sustituido por Obj-2
T S
Principio de sustitución de Liskov
Ley de Deméter
La Ley de Deméter (LoD por sus siglas en ingles Law of Demeter) o Principio de Menos Conocimiento
• En su forma general, la LoD es un caso específico de loose coupling. Esta directiva fue inventada en la Universidad
Northeastern (Boston, Massachusetts) a finales del año 1987, y puede ser sustancialmente resumida de las siguientes maneras:
• Cada unidad debe tener un limitado conocimiento sobre otras unidades y solo conocer aquellas unidades estrechamente relacionadas a la unidad actual. • Cada unidad debe hablar solo a sus amigos y no hablar con extraños.
Ley de Deméter
“Habla sólo con tus amigos”
Detallando un poco más, quiere decir que para un método M de una clase O sólo deberían invocarse métodos de los siguientes tipos de objetos:
• del propio objeto O
• de los parámetros que recibe el propio método M
• de cualquier objeto que instancie el propio método M