Sei sulla pagina 1di 50

Principios

de
Diseo Orientado
a Objetos
PRINCIPIOS DE DISEO DE CLASES
PRINCIPIO ABIERTO-CERRADO (OCP): Un
mdulo debe ser abierto para extensin pero
cerrado para modicacin.
Wikipidia: La nocin de que las en?dades de
so@ware deben estar abiertas para su
extensin, pero cerradas para su
modicacin.
Principio Abierto-Cerrado: Abierto a
extensiones Cerrado a modicaciones de
cdigo existente debido a extensiones
PRINCIPIOS DE DISEO DE CLASES
El Principio Open/Closed (Open/Closed Principle, OCP) fue acuado por
el Dr. Bertrand Meyer en su libro "Object Oriented So@ware
Construc?on" y bsicamente lo que nos dice este principio es que "las
en?dades de so@ware (clases, mdulos, funciones) deben estar
abiertas para extenderse, pero cerradas para modicacin".

Las clases que cumplen con OCP ?enen dos caracters?cas:


Son abiertas para la extensin; es decir, que la lgica o el comportamiento
de esas clases puede ser extendida en nuevas clases, usando herencia.
Son cerradas para la modicacin, y por tanto el cdigo fuente de dichas
clases debera permanecer inalterado.

Qu signica esto?: Que una en?dad ?ene que ser extendida sin
necesidad de ser modicada internamente. Por ejemplo, deberamos
poder ampliar la funcionalidad de una clase va herencia sin necesidad
de tener que modicar su comportamiento interno.


Principio abierto/cerrado

Las en7dades so8ware deben estar abiertas para su


extensin, pero cerradas para su modicacin
Bertran Meyer

Finalidad

Sistema funcionando (cerrado), pero Clase A Clase B


ampliable (abierto)
Conseguir cambios aadiendo nuevo
cdigo sin afectar al resto de elementos Diseo cerrado/cerrado
del diseo
Principio abierto/cerrado

Anlisis

Ambigedad
Clase A Clase B

La dependencia uno a uno se

transforma en una dependencia de
uno a muchos Diseo cerrado/cerrado

Ventajas

Clase A Abstracta B
Clase
Evita que cambios en un mdulo
afecten a otros mdulos


Clase B 1 Clase B2

Diseo abierto/cerrado
Principio abierto/cerrado

Anlisis
Estn abiertos para su extensin

Eso implica que el


Clase A Clase B
comportamiento de los mdulos

puede ser extendido. Se puede
Diseo cerrado/cerrado
hacer que un mdulo se comporte
de formas nuevas cuando los

Clase A Abstracta B
Clase
requisitos de la aplicacin
cambien.
Estn cerrados para su modicacin
Clase B 1 Clase B2
El cdigo fuente del mdulo es

inalterable. No se permite realizar
Diseo abierto/cerrado
cambios al cdigo fuente.
EJEMPLO: NO cumple el Principio abierto/cerrado

Se ?ene una aplicacin que es capaz de dibujar crculos y


cuadrados. Los crculos y los cuadrados deben ser dibujados en
un determinado orden, por lo tanto se crear una lista en el
orden apropiado de crculos y de cuadrados para que la
aplicacin recorra la lista en ese orden y dibuje cada crculo o
cada cuadrado.
U?lizando una versin estructurada que NO se ajusta al
principio abierto/cerrado, u?lizando lenguaje C, se puede
resolver este problema como se muestra en el ejemplo
EPDiseno0. Se puede observar que tanto la estructura
Cuadrado como la estructura Crculo ?enen el primer elemento
en comn, que no es ms que un iden?cador del ?po de
gura.
EJEMPLO: NO cumple el Principio abierto/cerrado

La funcin DibujaFiguras recorre la matriz de punteros a


elementos de ?po Figura, examinando el ?po de gura y
llamando a la funcin apropiada.

Sin embargo, la funcin DibujaFiguras no cumple el principio
abierto/cerrado porque no est cerrada a nuevos ?pos de
guras. Si se quiere extender esta funcin para dibujar
rectngulos, se ?ene que modicar la funcin DibujaFiguras.

VER <EPD0.CPP>
EJEMPLO: S cumple el Principio abierto/cerrado

En el Ejemplo EPDiseno0-1 se presenta la solucin al problema


planteado, pero de forma que cumpla el principio Abierto/
cerrado. Aprovechando las ventajas Programacin Orientada a
Objetos en C++. En este caso, se ha denido la clase Figura
como clase abstracta. Esta clase cuenta con un mtodo virtual
puro denominado Dibuja.
Las clases Crculo y Cuadrado son clases derivadas de la clase
Figura. Por su parte, la funcin DibujaFiguras no necesita
modicarse en el caso de que se aadan nuevas guras a la
jerarqua. De acuerdo con esto se puede extender el
comportamiento de la funcin DibujaFiguras sin modicar nada
en absoluto de su cdigo, cumpliendo as el principio abierto/
cerrado. VER <EPD0-1.CPP>
Ejercicio 1: Tarea 8
Agregue a los programas EDP0.CPP y EDP0-1.CPP
una nueva Figura Tringulo denida mediante
3 puntos y la funcin o mtodo Dibuja segn
corresponda. En EDP0.CPP debe usar cdigo
estrictamente C (estructurado) y en EDP0-1.CPP
cdigo estrictamente C++ (orientado a objetos.)

En cul programa result ms fcil y natural


agregar la nueva Figura Tringulo?
Principio de sus?tucin de Liskov

Cada clase que hereda de otra puede usarse como su padre


sin necesidad de conocer las diferencias entre ellas

El Principio de Sus?tucin de Liskov fue


acuado por Brbara Liskov (de ah el nombre
del principio) en el ao 1987 durante una
conferencia sobre Jerarqua y Abstraccin de
datos.
Principio de sus?tucin de Liskov

Cada clase que hereda de otra puede usarse como su padre


sin necesidad de conocer las diferencias entre ellas

Su principal come?do es la de asegurar en la herencia entre


clases de la Programacin Orientada a Objetos que una clase
derivada debe comportarse como la clase base. La denicin
es:
Debe ser posible u?lizar cualquier objeto instancia de una
subclase en lugar de cualquier objeto instancia de su superclase
sin que la semn?ca del programa escrito en los trminos de la
superclase se vea afectado
Principio de sus?tucin de Liskov
Otras deniciones de este principio son:

Cada clase que hereda de otra puede usarse como su padre sin necesidad de conocer
las diferencias entre ellas
Toda superclase debe soportar ser sus?tuida por una subclase, lo que en trminos de
contratos signica que las precondiciones de los mtodos de la subclase no sern
ms fuertes que las de la clase base, y sus pos condiciones no sern ms dbiles, es
decir, los mtodos derivados no deben esperar ms ni proveer menos que los
originales.
Los mtodos que usan punteros o referencias a clases base deben ser capaces de
u?lizar objetos de las clases derivadas sin tener conocimiento de ello (Mar?n96b),
tambin: Las clases derivadas deben ser u?lizables a travs de la interfaz de la clase
base, sin necesidad de que el usuario conozca la diferencia
Si por cada objeto O1 del ?po S existe un objeto O2 del ?po T tal que para todos los
programas P denidos en trminos de T y el comportamiento de P permanece
invariable cuando O1 es sus?tuido por O2, entonces S es un sub?po de T.
Cuadrado ES-UN Rectngulo? Cmo programarlo para
Respetar Principio de sus?tucin de Liskov?

Rectngulo Cuadrado
Rectngulo
Propiedades alto lado
ancho
ES UN ?
Operaciones SetAlto(x) SetLado(z)
SetAncho(y) GetLado()
GetAlto() Cuadrado
GetAncho()

Propiedades y mtodos
Principio de sus?tucin de Liskov

Anlisis

Ambigedad:
S es sub?po de T
Los programas no saben si
trabajan con objetos de T Obj-1 es un objeto de S
super?pos o de sub?pos
Obj-2 es un objeto de T
Ventajas S

El enunciado de Mar?n es
Para todo programa P ( T )
confuso: comportamiento P(Obj-1) = comportamiento P(Obj-2)
Los sub7pos deben ser sus7tuibles Cuando Obj-1 es sus?tuido por Obj-2
por los super7pos, pero la denicin

de sub?po se basa en la sus?tucin


Un ejemplo de violacin del
principio de sus?tucin de Liskov
Un ejemplo de violacin del
principio de sus?tucin de Liskov
Un ejemplo de violacin del
principio de sus?tucin de Liskov
Un ejemplo de violacin del
principio de sus?tucin de Liskov
Para ello, supongamos que a una determinado
cliente (otro programa), implementa la siguiente
funcin que espera un puntero o una referencia a un
objeto de ?po Rectngulo
Qu sucede si se le pasa se le pasa una instancia de la
clase Cuadrado?
Un ejemplo de violacin del
principio de sus?tucin de Liskov

ERROR
Versin que S respeta el principio de
sus?tucin de Liskov
Versin que S respeta el principio de
sus?tucin de Liskov
Ejercicio 2: Tarea 8
Agregue a la Jerarqua de clases del programa
EDP1.CPP dos nuevas Figuras: Rectngulo3D
denido mediante alto, ancho y largo y
Cuadrado3D en el que alto=ancho=largo
incluyendo los mtodos:
void EstableceAlto()
void EstableceAncho()
void EstableceLargo()
Principio de responsabilidad nica
Principio de nica Responsabilidad (Single responsibility principle)
La nocin de que un objeto solo debera tener una
nica responsabilidad
El Principio de responsabilidad nica (Single Responsability Principle - SRP) fue
acuado por Robert C. Mar7n en un arwculo del mismo wtulo y popularizado a
travs 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 trminos prc?cos, este principio establece que:
"Una clase debe tener una y solo una nica causa por la cual puede ser
modicada.
"Cada clase debe ser responsable de realizar una ac?vidad del sistema
Principio de responsabilidad nica
Principio de nica Responsabilidad (Single responsibility principle)
La nocin de que un objeto solo debera tener una
nica responsabilidad

Clase X
Finalidad Elementos asociados
Cliente P
Evitar que el cambio de una a la responsabilidad A
responsabilidad en una clase pueda
provocar fallos en las dems Cliente Q Elementos asociados
responsabilidades de la clase a la responsabilidad B

Evitar que los clientes de una clase
carguen con elementos que no u?lizan Diseo con una sola clase (incorrecto)
Principio de responsabilidad nica

Diseo con una sola clase Diseo con dos clases
(no adecuado)
Clase XA
Clase X Cliente P Elementos asociados
Cliente P Elementos asociados a la responsabilidad A
a la responsabilidad A

Cliente Q Elementos asociados Clase XB


a la responsabilidad B
Cliente Q Elementos asociados
a la responsabilidad B
Principio de responsabilidad nica

Anlisis

Clase X
Cliente P Responsabilidad A
Realidad del principio:
Cliente Q Responsabilidad B
Divisin salomnica puntual

Ambigedad: Diseo con una clase
Aumenta entre los elementos de
responsabilidades separadas

Clase XA
Aumenta entre la clase cliente hacia las Cliente P Responsabilidad A
clases separadas que no u?lizan

Disminuye entre la clase cliente hacia las
Clase XB
clases separadas que u?lizan
Cliente Q Responsabilidad B

Diseo con dos clases
Principio de inversin de dependencias

Los mdulos de alto nivel no deben depender de los


mdulos de bajo nivel. Ambos deben depender de las
abstracciones

Las abstracciones no deben depender de los detalles.
Los detalles deben depender de las abstracciones.
Robert C. Mar?n
Principio de inversin de dependencias
Un software que cumple sus requisitos pero que presenta alguna, o
todas, de las caractersticas siguientes tiene un mal diseo:

1. Rigidez: Es difcil de cambiar porque cada cambio tiene


demasiados efectos en otras partes del sistema.
2. Fragilidad: Cuando se realiza un cambio, partes inesperadas del
sistema dejan de funcionar.
3. Inmovilidad: Es difcil de reutilizar en otras aplicaciones porque
no puede separarse de la aplicacin actual.

El Principio de Inversin de dependencia ayuda a mantener nuestro


cdigo totalmente desacoplado, asegurndonos que dependemos de
abstracciones en vez de implementaciones concretas. La Inyeccin de
dependencias es una implementacin de este principio, aunque ambos
trminos se usan de forma intercambiable.
Principio de inversin de dependencias


Finalidad: Diseo tradicional
Conseguir que los cambios
en los mdulos de bajo Nivel Pol?ca
nivel no afecten a los
mdulos de alto nivel
Nivel Mecanismo
Facilitar la reu?lizacin de
los mdulos de alto nivel
Nivel U?lidad
Principio de inversin de dependencias

Diseo tradicional Diseo con inversin de dependencias

Pol?ca
Nivel Interfaz
Nivel Pol?ca Pol?ca Pol?ca

Mecanismo
Nivel Mecanismo
Nivel Interfaz
Mecanismo Mecanismo
Nivel U?lidad
U?lidad
Nivel
U?lidad
Ejemplo que NO cumple
Principio de inversin de dependencias
Como ejemplo se va a tomar un programa sumamente simple, el cual
va a tener la misin de mandar los caracteres que se introduzcan por
el teclado a un archivo en disco. El diagrama de estructura que se
correspondera con dicho programa se muestra en la Figura siguiente.
Ejemplo que NO cumple
Principio de inversin de dependencias
Ver <EPD2.CPP>
En este ejemplo las dos funciones de ms bajo nivel
LeerTeclado y GuardarArchivo son reutilizables, se pueden
utilizar en otros programas para acceder al teclado y para
guardar caracteres en un fichero de texto.

Sin embargo, la funcin Copiar, que es la que encierra la


poltica del proceso y sera deseable reutilizar, no se puede
reutilizar en ningn otro proceso que no haga referencia al
teclado y a un fichero. Ya que, se tiene que la funcin
Copiar es dependiente del disco y no puede reutilizarse en
otro contexto diferente.
Ejemplo que NO cumple
Principio de inversin de dependencias
As, si se quisiese aadir una nueva funcionalidad al
programa Copiar, por ejemplo que pudiese mandar los
datos a un fichero de texto o a la impresora, habra que
modificar el mdulo Copiar aadiendo una condicin que
seleccione el dispositivo en funcin de una bandera.

Esto aade cada vez ms interdependencias en el


sistema, de forma que cuantos ms dispositivos se
introduzcan mayor ser el grado de dependencia del
mdulo Copiar con varios mdulos de bajo nivel. Como
consecuencia se habr obtenido un cdigo rgido y frgil.
Ejemplo que S cumple
Principio de inversin de dependencias
Ver <EPD3.CPP>

Para solventar estas dependencias de la funcin de alto


nivel (Copiar) de las funciones de bajo nivel (Guardar
Archivo, EscribeImpresora) se debe buscar la forma de
independizar la funcin Copiar de los detalles que l
controla, para que de esta forma pueda ser reutilizado sin
problemas, esto es, se debe buscar un mdulo que copie
caracteres de cualquier dispositivo de entrada a cualquier
dispositivo de salida, para lo cual se debe tener presente el
principio de inversin de dependencias.
Ejercicio 3: Tarea 8
Agregue a los programas EDP2.CPP y EDP3.CPP una
nueva una nueva funcionalidad al a la funcin o
mtodo (segn corresponda) Copiar que luego de
leer el texto por teclado lo despliegue nuevamente
por pantalla. En EDP1.CPP debe usar cdigo
estrictamente C (estructurado) y en EDP3.CPP cdigo
estrictamente C++ (orientado a objetos.)

En cul programa result ms fcil y natural agregar


la nueva funcionalidad?
Ejemplo que S cumple
Principio de inversin de dependencias
Ver <EPDiseno3.CPP>
Ejemplo que S cumple
Principio de inversin de dependencias
El diagrama de clases anterior muestra una clase Copiar que contiene
dos clases abstractas, una clase abstracta Lector y otra clase
abstracta Escritor. De esta forma se tiene un ciclo trivial en el que la
clase Copiar obtiene un carcter del Lector y se la manda al Escritor,
pero de forma totalmente independiente de los mdulos de bajo nivel.
De esta forma se han invertido las dependencias, la clase Copiar
depende de abstracciones, y los lectores y escritores especializados
dependen de las mismas abstracciones.

De esta forma ahora se puede reutilizar la clase Copiar de forma


independiente de los dispositivos fsicos. Se pueden aadir nuevos
tipos de lectores y de escritores sin que la clase Copiar dependa en
absoluto de ellos.
Principio de separacin de la interfaz
Los clientes no deben ser forzados a depender de
interfaces que no u7lizan
Robert C. Mar?n

Bsicamente lo que nos quiere decir este principio es que las
clases que implementen una interfaz o una clase abstracta no
deberan estar obligadas a tener partes que no van a u?lizar.

Una interfaz es un contrato que debe cumplir una clase, y tales


contratos deben ser especcos, no genricos; esto nos
proporcionar una forma ms gil de denir una nica
responsabilidad por interfaz - de otra forma, violaramos adems
el Principio de Responsabilidad nica
Principio de separacin de la interfaz
Los clientes no deben ser forzados a depender de
interfaces que no u7lizan
Robert C. Mar?n

Otras deniciones de este principio son:
La implementacin 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 usarn.
Es mejor tener interfaces especcos para cada cliente que
uno de propsito general, o lo que es lo mismo, no
deberamos obligar a los clientes a depender de mtodos
que no u?lizan.
Principio de separacin de la interfaz

Diseo con una interfaz Diseo con dos interfaces
(incorrecto)
interfaz ZC
Interfaz Z Cliente C Mtodos que u?liza
Cliente C Mtodos que u?liza el cliente C
el cliente C

Cliente D Mtodos que u?liza


el cliente D
Interfaz ZD
Cliente D Mtodos que u?liza
el cliente D
Principio de separacin de la interfaz

Anlisis

Interfaz Z
Cliente C Mtodos cliente C
Extensin del principio de
Cliente D Mtodos cliente D
responsabilidad nica

Ambigedad Diseo con una interfaz
Aumenta entre los mtodos de
interfaces separadas

Interfaz ZC
Aumenta entre la clase cliente hacia los Cliente C Mtodos cliente C
mtodos de las interfaces no u?liza

Interfaz ZD
Cliente D Mtodos cliente D

Diseo con dos interfaces
Ejemplo que NO cumple
Principio de separacin de la interfaz
Supngase que se est desarrollando un sistema de
seguridad, en el que existe una clase que es Puerta.
Considrese ahora una puerta que cuando lleve abierta
un determinado ?empo haga sonar una alarma, y cuya
clase va a denominarse PuertaConAlarma.
Para conseguir este obje?vo, los objetos de la clase
PuertaConAlarma deben comunicarse con los objetos
de la clase Temporizador que lleva el control del
?empo.
Ejemplo que NO cumple
Principio de separacin de la interfaz
Ejemplo que NO cumple
Principio de separacin de la interfaz
Se ha forzado a la clase Puerta, y por tanto a la clase
PuertaConAlarma, a heredar de ClienteTemporizador.
Esta solucin es problem?ca, debido a que ahora
Puerta depende de ClienteTemporizador, y no todas las
puertas necesitan de este control de ?empo, de hecho
la abstraccin original de Puerta no contemplaba en
absoluto el ?empo. Segn este diseo, todas las
puertas que se deriven de Puerta heredan
innecesariamente de la clase ClienteTemporizador.
Ejemplo que S cumple
Principio de separacin de la interfaz
La solucin a este problema es aplicar el principio de
separacin de la interfaz en el diseo, como se puede
apreciar en la.
Aqu se ha hecho uso de la herencia ml?ple, de forma
que la clase PuertaConAlarma herede de la clase
Puerta y de la clase ClienteTemporizador, de esta forma
los clientes de las dos clases bases podrn recibir
objetos de PuertaConAlarma, u?lizando el mismo
objeto a travs de interfaces separadas.
Ejemplo que S cumple
Principio de separacin de la interfaz
Ley de Demter

La Ley de Demter (LoD por sus siglas en ingles Law of


Demeter) o Principio de Menos Conocimiento

En su forma general, la LoD es un caso especco de loose


coupling. Esta direc?va fue inventada en la Universidad
Northeastern (Boston, Massachuse}s) a nales del ao 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 extraos.
Solo hablar con sus amigos inmediatos.
Ley de Demter

Habla slo con tus amigos


Detallando un poco ms, quiere decir que para un mtodo M de
una clase O slo deberan invocarse mtodos de los siguientes
?pos de objetos:
del propio objeto O
de los parmetros que recibe el propio mtodo M
de cualquier objeto que instancie el propio mtodo M
de cualquier atributo de O
Gracias.

Potrebbero piacerti anche