PDF de programación - Principio Open/Solid

Principio Open/Solidgráfica de visualizaciones

Publicado el 14 de Enero del 2017
1.412 visualizaciones desde el 14 de Enero del 2017
488,3 KB
5 paginas
Creado hace 13a (23/12/2010)
Principio Open/Closed

Este es el segundo de una serie de cinco artículos que describen los principios SOLID y su aplicación
en la Programación Orientada a Objetos. Después de examinar en nuestra entrega anterior el Principio
de Responsabilidad Única, este mes nos adentramos en otro de los principios, que además guarda una
estrecha relación con el primero: el Principio Open/Closed.

T

odas las aplicaciones cambian
durante su ciclo de vida, y siempre vendrán nuevas
versiones tras la primera release. No por ello debe-
mos adelantarnos a desarrollar características que
el cliente podría necesitar en el futuro; si nos pusié-
ramos en el papel de adivinos, seguramente fallaría-
mos y probablemente desarrollaríamos caracterís-
ticas que el cliente nunca necesitará. El principio
YAGNI ("You Ain’t Gonna Need It" o "No vas a nece-
sitarlo"), utilizado en la Programación Extrema, pre-
viene de implementar nada más que lo que real-
mente se requiera. La idea es desarrollar ahora sobre
los requisitos funcionales actuales, no sobre los que
supongamos que aparecerán dentro de un mes.

La actitud de adelantarnos a los acontecimientos
es un mecanismo de defensa que en ocasiones acu-
samos los desarrolladores para prevenir lo que tarde
o temprano será inevitable: la modificación. Lo úni-
co que podemos hacer es minimizar el impacto de
una futura modificación en nuestro sistema, y para
ello es imprescindible empezar con un buen diseño,
ya que la modificación de una clase o módulo de una
aplicación mal diseñada generará cambios en casca-
da sobre las clases dependientes que derivarán en
unos efectos indeseables. La aplicación se convierte,
así, en rígida, impredecible y no reutilizable.

Ahora bien, ¿cómo debemos plantear nuestras
aplicaciones para que se mantengan estables ante
cualquier modificación?

El Principio Open/Closed

El Principio Open/Closed (Open/Closed Principle,
OCP) fue acuñado por el Dr. Bertrand Meyer en su

libro "Object Oriented Software Construction" [1] y
afirma que:

Una clase debe estar abierta a extensiones, pero

cerrada a las modificaciones.

OCP es la respuesta a la pregunta que hacía-
mos anteriormente, ya que argumenta que debería-
mos diseñar clases que nunca cambien, y que cuan-
do un requisito cambie, lo que debemos hacer es
extender el comportamiento de dichas clases aña-
diendo código, no modificando el existente.

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 pue-
de ser extendida en nuevas clases.

• Son cerradas para la modificación, y por tanto el
código fuente de dichas clases debería perma-
necer inalterado.

Podría parecer que ambas características son
incompatibles, pero eso no es así. Veamos un ejem-
plo de una clase que rompe con OCP. Supongamos
un sistema de gestión de proyectos al estilo de
Microsoft Project. Obviemos de momento la com-
plejidad real que existe en dicho sistema, y centré-
monos únicamente en la entidad Tarea, tal y como
muestra la figura 1. Dicha clase viene determinada
por uno de los estados Pendiente, Finalizada o
Cancelada, representados mediante la enumera-
ción EstadosTarea. Además, la clase implementa
dos métodos, Cancelar y Finalizar que cambian,
si es posible, el estado de la tarea. En el listado 1

José Miguel Torres
MVP de Device Application Development

public void Finalizar()
{

switch (_estadoTarea)
{

case EstadosTarea.Pendiente:

// finalizamos
break;

case EstadosTarea.Finalizada:

case EstadosTarea.Cancelada:

throw new ApplicationException("Tarea ya finalizada");

throw new ApplicationException("Imposible finalizar. Tarea cancelada");

default:

throw new ArgumentOutOfRangeException();

public void Finalizar()
{

switch (_estadoTarea)
{

case EstadosTarea.Pendiente:

// finalizamos
break;

case EstadosTarea.Finalizada:

case EstadosTarea.Cancelada:

case EstadosTarea.Pospuesta:

throw new ApplicationException("Tarea ya finalizada");

throw new ApplicationException("Imposible finalizar. Tarea cancelada");

throw new ApplicationException("Imposible finalizar. Tarea no completada");

default:

throw new ArgumentOutOfRangeException();

Figura 1

podemos ver la implementación inicial
del método Finalizar.

Un cambio típico solicitado por el
cliente de la aplicación sería la adición de
un nuevo estado para controlar las tare-
as que se han pospuesto, con lo que la
adaptación a esta modificación podría ser
la expuesta en el listado 2. Aparentemente,
parece una modificación trivial; sin embar-
go, este cambio puede replicarse en otros
métodos o clases que utilicen la enume-
ración EstadosTarea, de forma que en
nuestro caso también deberíamos modi-
ficar el método Cancelar (listado 3).

En definitiva, por cada nuevo estado
que implementemos tendremos que
identificar todas las clases que lo utilizan
(tanto la clase Tarea como las clases lógi-
camente involucradas) y modificarlas, vio-
lando no únicamente OCP sino también
el Principio DRY ("Don’t Repeat Yourself",
"No te repitas"), otro principio que pre-
tende reducir al máximo cualquier tipo
de duplicación. En este tipo de modifi-
caciones existe una alta probabilidad de
olvidar modificar algún método relacio-
nado con el nuevo estado implementa-
do en el enumerador EstadosTarea, lo
que elevaría la probabilidad de aparición
de un nuevo bug.
Fundamentos de la orientación
a objetos
La cuestión se centra en cómo minimizar
el impacto de una modificación en nues-
tro sistema, sin comprometer OCP; esto
es, manteniendo la "simbiosis" entre las
dos características del principio: abierto
en extensión y cerrado en modificación.
Volvamos a la entidad Tarea del
ejemplo anterior. Por lo que hemos
podido ver, los métodos dependen en
gran medida del estado de la tarea. Así,

}

}

Listado 1

}

}

Listado 2

}

}

Listado 3

public void Cancelar()
{

switch (_estadoTarea)
{

case EstadosTarea.Pendiente:

// cancelamos
_estadoTarea = EstadosTarea.Cancelada;
break;

case EstadosTarea.Finalizada:

throw new ApplicationException("Imposible cancelar. Tarea finalizada");

case EstadosTarea.Cancelada:

throw new ApplicationException("Tarea ya cancelada");

case EstadosTarea.Pospuesta:

// cancelamos
_estadoTarea = EstadosTarea.Cancelada;
break;

default:

throw new ArgumentOutOfRangeException();

a
í
n
a
M
t
e
N
t
o
d

11

class EstadosTareaHelper
{

public virtual void Finalizar(EstadosTarea estado)
{

switch ( estado) {

case EstadosTarea.Pendiente:

// finalizamos

case EstadosTarea.Pospuesta:

throw new ApplicationException("Imposible finalizar. Tarea no completada");

default:

throw new ArgumentOutOfRangeException();

}

}

public virtual void Cancelar(EstadosTarea estado)
{

switch (estado) {

// ...
// cancelamos

}

}

public virtual void Posponer(EstadosTarea estado)
{

switch (estado) {

// ...
// posponemos

}

}

}

Listado 4

Cuando un requisito cambie, lo que debemos
hacer es extender el comportamiento aña-
diendo código, y no modificando el existente

una tarea podrá finalizarse o cancelarse dependien-
do de su estado previo, pues no podremos cancelar
una tarea que haya sido finalizada. De la misma for-
ma, introduciendo el nuevo estado EstadosTarea.
Pospuesta implementaríamos un nuevo método lla-
mado Posponer, cuya lógica sería obvia: únicamente
podría posponerse una tarea que estuviera en esta-
do pendiente. En definitiva, todo gira alrededor del
estado de la tarea, y por tanto el comportamiento de
la misma dependerá del estado en que se encuentre.
Una opción sería encapsular dicho estado en una cla-
se auxiliar e implementar en ella los métodos Fina‐
lizar, Cancelar y Posponer, mediante los cuales defi-
nimos el comportamiento, tal y como se muestra en
el listado 4, para luego delegar los métodos del obje-
to Tarea hacia dicha clase.

a
í
n
a
M
t
e
N
t
o
d

12

Pese a que hayamos extraído y aislado el estado
de la entidad Tarea, aún no hemos resuelto el pro-
blema. De hecho, ahora hemos aislado la responsa-
bilidad en la clase EstadosTareaHelper; sin embargo,
estamos algo más cerca de la solución. Estudiemos
de nuevo los estados -métodos- de la clase Estados‐
TareaHelper. La lógica de cada acción está escrita en
todos los métodos y por tanto se repite; es decir, todos
los métodos contemplan la opción de Finalizar una
tarea, y en base a ello actúan de una forma u otra. La
operación Posponer no podrá ejecutarse si el estado
de la tarea es Cancelada, y la operación Cancelar úni-
camente podrá ejecutarse si el estado es Pendiente.
A través de este razonamiento, podemos detectar un
patrón: un mismo contrato –los métodos– y dife-
rentes comportamientos en base a un estado. Esto
en OO puede ser solucionado mediante polimorfis-
mo, como se muestra en el listado 5.

Básicamente, lo que hemos hecho es crear una clase
por cada estado en lugar de tener una única clase cuyos
métodos están basados en sentencias condicionadas por
el estado de la tarea (switch o if). Además, con esta
nueva implementación hemos delegado la responsabili-
dad de finalizar, cancelar o posponer a una nueva clase

abstract class EstadoTareaBase
{

protected Tarea _tarea;

public abstract void Finalizar();
public abstract void Cancelar();
public abstract void Posponer();

}

class EstadoTareaPendiente : EstadoTareaBase
{

public override void Finalizar()
{

// finalizamos

public override void Cancelar()
{

// cancelamos

public override void Posponer()
{

// posponemos

class EstadoTareaFinalizada : EstadoTareaBase
{

public override void Finalizar()
{

throw new ApplicationException("Tarea ya finalizada");

public override void Cancelar()
{

throw new ApplicationException("Imposible cancelar. Tarea finalizada");

public override void Posponer()
{

throw new ApplicationException("Imposible posponer. Tarea finalizada");

}

}

}

}

}

}

}

}

}

}

class EstadoTareaCancelada : EstadoTareaBase
{

public override void Finalizar()
{

throw new ApplicationException("Imposible finalizar. Tarea cancelada");

public override void Cance
  • Links de descarga
http://lwp-l.com/pdf221

Comentarios de: Principio Open/Solid (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad