Patrones de Diseño (copia)

23
República Bolivariana de Venezuela Ministerio de Poder popular para la Educación Universitaria Universidad Politécnica Territorial del Oeste de Sucre “Clodosbaldo Russian” Cumaná Estado Sucre Patrones de Diseño de Software “Decorator”

Transcript of Patrones de Diseño (copia)

República Bolivariana de Venezuela

Ministerio de Poder popular para la Educación Universitaria

Universidad Politécnica Territorial del Oeste de Sucre “Clodosbaldo Russian”

Cumaná Estado Sucre

Patrones de Diseño de Software

“Decorator”

Cumaná, Junio de 2013

Introducción

El concepto de patrón software, más concretamente el concepto de patrón

de diseño, se hizo popular dentro del mundo del desarrollo del software en 1995

con la publicación del libro Design Patterns: Elements of Reusable Object-Oriented

Software, cuyos autores son Erich Gamma, Richard Helm, Ralph Jonhson y John

Vlissides (normalmente referenciados como la Banda de los Cuatro – The Gang of

Four – o simplemente por GoF).

Realmente el uso del término patrón, con el significado que actualmente se

le da en la Ingeniería del Software y más concretamente en el área de la

tecnología de objetos, se deriva de los trabajos del arquitecto Christopher

Alexander desde mediados de los años 60.

Existen varios tipos de patrones de diseño, entre los que destacan:

Adaptador, Factory, MVC, Registry, Decorator, entre otros. A continuación

explicaremos detalladamente el uso del patrón Decorator.

Contenido

Patrones de Diseño de Software

Según Brad Appleton 1997, un patrón es una unidad de información

instructiva con nombre que captura la estructura esencial y la comprensión de una

familia de soluciones exitosas probadas para un problema recurrente que ocurre

dentro de un cierto contexto y de un sistema de fuerzas.

Para James Coplien 1992, cada patrón es una regla constituida por tres

partes, la cual expresa una relación entre un cierto contexto, un cierto sistema de

fuerzas que ocurren repetidamente en ese contexto, y una cierta configuración de

software que permite a estas fuerzas resolverse así mismas.

Un patrón de diseño es una descripción de clases y objetos

comunicándose entre sí, adaptado para resolver un problema de diseño general en un

contexto particular. Se describen en forma textual, acompañados de diagramas

(habitualmente de clases e interacción) y pseudocódigo.

Cada patrón describe un problema que ocurre una y otra vez en nuestro

entorno y describe también el núcleo de l a so l uc i ón de p rob lemas , de

f o rma que pueda utilizarse un millón de veces sin tener que hacer dos

veces lo mismo.

Motivación e importancia en el uso de patrones

Los patrones de diseño son importantes de usar, porque sirven de guía

para resolver problemas comunes en programación. Al aprenderlos, aprenderás a

identificar de mejor manera los problemas que vas a tener, antes de que

aparezcan, y aprenderás qué solución es la que mejor se aplica a tu problema.

La idea de los patrones de diseño es especificar soluciones buenas y

determinar sus características de algún modo para que puedan ser integradas en

los diseños de aplicaciones incluso por diseñadores no expertos.

Clasificación

Según su propósito:

Patrones de creación. Se refieren a la creación de instancias.

Dentro de los patrones de creación tenemos:

o Abstract Factory . Proporciona una interfaz para crear familias de objetos

o que dependen entre sí, sin especificar sus clases concretas.

o Builder (Constructor). Separa la construcción de un objeto complejo de

su representación, de forma que el mismo proceso de construcción

pueda crear diferentes representaciones.

o Factory Method (Método de Fábrica). Define una interfaz para crear un

objeto, pero deja que sean las subclases quienes decidan qué clase

instanciar. Permite que una clase delegue en sus subclases la creación

de objetos.

o Prototype (Prototipo). Especifica los tipos de objetos a crear por medio

de una instancia prototípica, y crear nuevos objetos copiando este

prototipo.

Patrones estructurales. Se refieren a las relaciones entre clases y/u

objetos. Éstos son:

o Adapte r . Convierte la interfaz de una clase en otra distinta que es la que

esperan los clientes. Permiten que cooperen clases que de otra manera

no podrían por tener interfaces incompatibles.

o Bridge . Desvincula una abstracción de su implementación, de manera

que ambas puedan variar de forma independiente.

o Decorator . Añade dinámicamente nuevas responsabilidades a un objeto,

proporcionando una alternativa flexible a la herencia para extender la

funcionalidad.

o Facade . Proporciona una interfaz unificada para un conjunto de

interfaces de un subsistema. Define una interfaz de alto nivel que hace

que el subsistema es más fácil de usar.

o Flyweight . Usa el compartimiento para permitir un gran número de

objetos de grano fino de forma eficiente. Proxy. Proporciona un sustituto

o representante de otro objeto para controlar el acceso a éste.

o Composite . Permite combinar objetos en estructuras de árbol para

representar jerarquías. Permite además, agrupar varios objetos como si

fueran uno solo.

Patrones de comportamiento. Caracterizan la forma en que las clases u

objetos interactúan y distribuyen sus responsabilidades (servicios).

o Chain of Responsibility. Evita acoplar el emisor de una petición a su

receptor, al dar a más de un objeto la posibilidad de responder a la

petición. Crea una cadena con los objetos receptores y pasa la petición

a través de la cadena hasta que esta sea tratada por algún objeto.

o Command . Encapsula una petición en un objeto, permitiendo así

parametrizar a los clientes con distintas peticiones, encolar o llevar un

registro de las peticiones y poder deshacer la operaciones.

o Interpreter . Dado un lenguaje, define una representación de su

gramática junto con un intérprete que usa dicha representación para

interpretar las sentencias del lenguaje.

o Iterator . Proporciona un modo de acceder secuencialmente a los

elementos de un objeto agregado sin exponer su representación interna.

o Mediator . Define un objeto que encapsula cómo interactúan un conjunto

de objetos. Promueve un bajo acoplamiento al evitar que los objetos se

refieran unos a otros explícitamente, y permite variar la interacción entre

ellos de forma independiente. Memento. Representa y externaliza el

estado interno de un objeto sin violar la encapsulación, de forma que

éste puede volver a dicho estado más tarde.

o Observer . Define una dependencia de uno-a-muchos entre objetos, de

forma que cuando un objeto cambia de estado se notifica y actualizan

automáticamente todos los objetos.

o State . Permite que un objeto modifique su comportamiento cada vez que

cambia su estado interno. Parecerá que cambia la clase del objeto.

o Strategy . Define una familia de algoritmos, encapsula uno de ellos y los

hace intercambiables. Permite que un algoritmo varíe

independientemente de los clientes que lo usan.

o Template Method . Define en una operación el esqueleto de un algoritmo,

delegando en las subclases algunos de sus pasos. Permite que las

subclases redefinan ciertos pasos del algoritmo sin cambiar su

estructura.

o Visitor . Representa una operación sobre los elementos de una

estructura de objetos. Permite definir una nueva operación sin cambiar

las clases de los elementos sobre los que opera.

o Memento . Se utiliza para guardar el estado de un objeto y poder luego

restaurar el objeto a un estado previo.

o Proxy. Proporciona un representante o delegado que se encarga de

controlar el acceso a un objeto, generalmente por motivos de eficiencia.

Según su ámbito:

Patrones de clases. Tratan con relaciones de herencia (estática) entre

clases.

Patrones de objetos. Se refieren a relaciones de composición entre objetos,

que pueden cambiar en tiempo de ejecución y son más dinámicas.

Patrón Decorator

Este patrón de diseño permite añadir responsabilidades adicionales a un

objeto de forma dinámica. Proporciona una alternativa flexible a la subclasificación

para añadir funcionalidad, además, se usa cuando es imposible la extensión de

funcionalidad por herencia, por ser aquella imprevisible en tipo y número.

Aporta una mayor flexibilidad que la herencia estática, permitiendo, entre

otras cosas, añadir una funcionalidad dos o más veces. También evita concentrar

en lo alto de la jerarquía clases guiadas por las responsabilidades, es decir, que

pretenden (en vano) satisfacer todas las posibilidades. De esta forma las nuevas

funcionalidades se componen de piezas simples que se crean y se combinan con

facilidad, independientemente de los objetos cuyo comportamiento extienden.

Responde a la necesidad de agregar funcionalidad a un objeto por medio

de la asociación de clases. Es un objeto con el que se puede ejecutar

funcionalidades de varias clases a la vez.

Propósito del Patón Decorator

Permite añadir responsabilidades extra a objetos concretos de manera

dinámica

Proporciona una alternativa flexible a la herencia para extender

funcionalidad, también conocido como wrapper.

Implementación

Este patrón soluciona problemas de una manera mucho más sencilla y

extensible. Se crea a partir de Ventana la subclase abstracta VentanaDecorator y,

heredando de ella, BordeDecorator y BotonDeAyudaDecorator. VentanaDecorator

encapsula el comportamiento de Ventana y utiliza composición recursiva para que

sea posible añadir tantas "capas" de Decorators como se desee. Podemos crear

tantos Decorators como queramos heredando de VentanaDecorator.

El decorador debe cumplir la interfaz de la clase Componente para que el

cliente no distinga entre objetos básicos y decorados.

Cuando sólo exista la posibilidad de añadir un tipo de funcionalidad a los

objetos básicos se puede omitir la clase abstracta Decorador. En general

esto no es así y además conviene ponerla porque proporciona mayor

flexibilidad al diseño.

Se debe mantener la clase Componente o Component ligera. Así la

definición de los datos de representación debería hacerse en las subclases

porque si no se hará a las clases decoradoras muy pesadas para poder ser

usadas de forma anidada. Además añadir demasiada funcionalidad en la

interfaz Componente aumenta la probabilidad de que se pongan

características que para un caso en concreto no se utilicen.

Motivación

A veces se quiere añadir funcionalidad a un objeto concreto, no a una clase

entera.

Ej: Un toolkit para GUIs proporciona soporte para añadir marcos, barras de des-

plazamiento... a componentes.

Solución:

Herencia: no es flexible, la funcionalidad se añade estáticamente

Definir una clase “decoradora” que envuelve al componente, y le proporciona la

funcionalidad adicional requerida: más flexible, transparente al cliente, se pueden

anidar decoradores

Patrón de Diseño Estructural Decorator

Decorator es un patrón de diseño estructural, cuyo objetivo principal es el de

evitar un sin fin de clases herederas.

La idea de decorar un objeto (o envolver, como también se conoce), es

agregarle nuevas funcionalidades o características al mismo.

Estas nuevas funcionalidades se pueden lograr mediante el uso de herencia

simple, pero hay ocasiones en que la herencia genera muchas

combinaciones.

Con Decorator se quiere solucionar los siguientes problemas:

Se tiene un objeto al que se le quiere aplicar una nueva característica.

La característica se le debe aplicar dinámicamente.

No se sabe qué característica es la que se va aplicar.

Para lograr esto, se utiliza el siguiente patrón:

Hay algunos puntos a tomar en cuenta de este patrón de diseño:

Hay clases genéricas que van a ser heredadas, de manera que los métodos

del objeto a decorar sean accesibles.

Se crea un objeto “decorador” que conozca todas las características que se

van a agregar.

Se crean los objetos de características que las agregan.

Participantes

Component (VisualComponent): define la interfaz de los objetos a los que

se puede añadir responsabilidades de manera dinámica.

ConcreteComponent (TextView): define un objeto al que añadir responsa-

bilidades de manera dinámica.

Decorator: mantiene una referencia al objeto componente y define una in-

terfaz conforme a la del componente.

ConcreteDecorator (BorderDecorator, ScrollDecorator): añade responsabi-

lidades al componente al que referencia.

Colaboradores

El decorador redirige las peticiones al componente asociado y opcionalmente

puede realizar tareas adicionales antes o/y después de redirigir la petición.

Consecuencias

Es más flexible que la herencia estática.

Las responsabilidades se añaden y eliminan dinámicamente.

Facilita definir una propiedad varias veces (ej. doble marco).

Evita que las clases más altas en la jerarquía estén demasiado cargadas de

funcionalidad y sean complejas.

No hay precio que pagar por propiedades que no se usan.

Facilita la definición de nuevos decoradores.

Un decorador y el componente al que se refiere no son idénticos (esto es,

tienen distinto identificador).

Provoca la creación de muchos objetos pequeños parecidos y encadena-

dos, complicando la depuración.

Aplicabilidad

El patrón Decorator se usa:

Para añadir responsabilidades a objetos concretos de manera dinámica y

transparente, esto es, sin afectar a otros objetos

Para responsabilidades que se pueden añadir y quitar

Cuando la herencia sea impracticable, porque implique crear múltiples

subclases para todas las combinaciones posibles (ejm. TextViewScroll,

TextViewScrollBorder, ...)

Ejemplo del Patrón Decorator usando PHP

<?php

interface iCoffee

{

public function getBaseCost();

}

class Coffee implements iCoffee

{

protected $_baseCost = 0;

public function getBaseCost()

{

return $this->_baseCost;

}

}

class BlackCoffee extends Coffee

{

public function __construct()

{

$this->_baseCost = 5;

}

}

abstract class CoffeeDecorator implements iCoffee

{

protected $_coffee;

public function __construct(iCoffee $Coffee)

{

$this->_coffee = $Coffee;

}

}

class WithCream extends CoffeeDecorator

{

public function getBaseCost()

{

return $this->_coffee->getBaseCost() + 1.5;

}

}

class WithMilk extends CoffeeDecorator

{

public function getBaseCost()

{

return $this->_coffee->getBaseCost() + 4;

}

}

class WithChocolate extends CoffeeDecorator

{

public function getBaseCost()

{

return $this->_coffee->getBaseCost() + 5;

}

}

$coffee = new WithChocolate(new WithMilk(new WithCream(new BlackCoffee())));

echo 'El precio del cafe es: $' . $coffee->getBaseCost();

Diagrama de Clases del Patrón Decorator

Ventajas del Patrón Decorator

Amplía la funcionalidad de una interfaz al tiempo que la mantiene igual y se

hace dinámicamente.

No altera la funcionalidad existente, solo añade más funciones.

Las responsabilidades se pueden añadir o quitar.

Desventajas del Patrón Decorator

Si estas decorando demasiado a un objeto, vas a terminar con un montón

de decoraciones (clases) pequeñas. Si tu código está muy desordenado,

entonces vas a tener pesadillas tratando de encontrar las clases decorati-

vas.

Aumento en la complejidad a la hora de instanciar el objeto a ser decorado.

Al instanciarlo, debes envolverlo en quién sabe cuántas decoraciones, así

que es importante usar el sentido común.

El exceso de decoraciones que agregan métodos a un objeto, puede ser

problemático si no se especifican que decoraciones extienden el API del ob-

jeto y cuáles son los nuevos métodos que se aportan. Esta situación tam-

bién nos pueden causar dificultades cuando hay quedebuguear una aplica-

ción.

En algunos casos el programador debe aprender el orden en el cual las de-

coraciones deben ser instanciadas. Si vamos al último ejemplo, si el progra-

mador usa el decorador UpperCaseal final, los tags dentro del HTML van a

ser transformados a mayúsculas también. Por eso es vital que el programa-

dor entienda cuál es la intención detrás de cada decoración.

¿Es aplicable el patrón asignado para el diagrama de clase de su proyecto?

El patrón de diseño de software asignado (Decorator), no es aplicable al

diagrama de clases de nuestro proyecto, debido a que ninguna clase hereda de

otra clase.

Diagrama de Clase del Proyecto

Conclusiones

El patrón Decorator, nos permite extender objetos incluso en situaciones

cuando la extensión vía herencia no es viable o no es necesaria. Adicional-

mente nos ayuda a conservar el principio de Abierto/Cerrado, en donde se

dicta que cada entidad debe estar abierta a extensión pero cerrada a modi-

ficación.

Las decoraciones evitan la labor de crear clases complejas con mucho códi-

go, que en la mayoría de los casos no será evaluado. Se puede usar distin-

tas combinaciones (o secuencias) de decoraciones para generar distintos

comportamientos o resultados.

Para que una solución sea considerada un patrón debe poseer ciertas ca-

racterísticas. Una de ellas es que debe haber comprobado su efectividad

resolviendo problemas similares. 

Bibliografía

http://kuainasi.ciens.ucv.ve/ideas07/documentos/tutoriales/

TUTORIALErnestoPimentel.pdf

http://es.scribd.com/doc/29568742/PATRONES-DE-DISENO-DE-SOFTWARE

http://zarza.usal.es/~fgarcia/doc/patrones1.pdf

http://www.ecured.cu/index.php/Patr%C3%B3n_de_dise%C3%B1o_de_software

http://es.scribd.com/doc/58071962/Informe-Patron-de-Diseno-Decorador-

Decorator

http://webdiis.unizar.es/~jmerse/IS-2/TeoriaPatronesV2_2.pdf