Como Aplicar Patrones de Diseño Estructurales en Aplicaciones Web Con Java
Como Aplicar Patrones de Diseño Estructurales en Aplicaciones Web Con Java
Como Aplicar Patrones de Diseño Estructurales en Aplicaciones Web Con Java
Cochabamba – Bolivia
2018
Dedico este documento a mi Madre,
ii
Tabla de Contenido
TABLA DE CUADROS, GRAFICOS Y FIGURAS 4
Resumen 5
Introducción 6
1 Generalidades 7
2 Metodología 8
3.4 Aspectos para tomar en cuenta al usar el Patrón de diseño Decorador o Decorator 28
3.6 Aspectos a tomar en cuenta al usar el Patrón de diseño Flyweight o Peso Ligero 37
4 Conclusiones 43
5 Bibliografía 45
TABLA DE CUADROS, GRAFICOS Y FIGURAS
4
Resumen
Los patrones de diseño más conocidos se dividen en distintos grupos según el tipo de problema
que resuelven:
Patrones Estructurales, especifican la forma en la que unas clases se relacionan con otras,
separan la interfaz de la implementación. Los más conocidos son: Adaptador (Adapter), Puente
(Bridge), Compuesto (Composite), Decorador (Decorator), Fachada (Facade), Peso Ligero
(Flyweight), Proxy.
5
Introducción
Este documento propone ver el uso de patrones de diseño estructurales en aplicaciones Web
con java. Justificando el uso de estos patrones de diseño en el desarrollo de aplicaciones web.
En los últimos tiempos, las empresas e instituciones han visto que el uso del internet se ha
incrementado en estos últimos años, para mantenerse y hacerse conocer en el mercado deben
incursionar en el uso de aplicaciones web. Debido a esto existe un incremento en la necesidad
de desarrollar aplicaciones Web.
Otro punto que se debe tomar en cuenta, es que no solo una persona trabaja en el desarrollo de
una aplicación, al hacer uso de los patrones de diseño se realizará una codificación estándar y
se tendrá una mejor comunicación entre los desarrolladores y esto significaría un menor esfuerzo
y tiempo en el desarrollo de la aplicación.
Este documento contribuirá a entender un poco más estos patrones y en qué casos se puede
usar al desarrollar las aplicaciones web.
6
1 Generalidades
El desarrollo de software ha pasado por varias fases, las cuales le han permitido madurar poco
a poco hasta llegar a lo que se conoce ahora. Cuando el desarrollo de aplicaciones comenzó, no
se pensaba que para llevar un problema a una solución sistemática era necesario realizar un
análisis y un diseño, sino que se llegaba directamente a la implementación, sin manejar una
gestión detallada del mismo. Esto causaba en el trascurso del desarrollo una serie de
inconvenientes que no permitía que las aplicaciones fueran flexibles en cuanto a su
mantenimiento y/o adaptabilidad a diferentes ambientes. Más adelante, se vio la necesidad de
aplicar prácticas exitosas y controladas que otras ciencias usaban y era posible adaptarlas a la
ciencia computacional como los patrones de diseño entre otros. Estas técnicas de desarrollo
adoptadas han permitido a través del tiempo que el desarrollo de aplicaciones software se haga
de una manera gestionada, teniendo mayor control del mismo, que sea flexible en cuanto a
cambios que se vayan a realizar y que la mantenibilidad del mismo sea menos compleja.
Los patrones de diseño son importantes en la definición y creación de una aplicación web ya que
sirven para definir la arquitectura que se va a usar y los frameworks que se adaptan a la misma.
Los patrones estructurales, se enfocan en cómo las clases y objetos se componen para formar
estructuras mayores, ellos describen cómo las estructuras compuestas por clases crecen para
crear nuevas funcionalidades, a manera de agregar a la estructura flexibilidad y que la misma
7
pueda cambiar en tiempo de ejecución, lo cual es imposible con una composición de clases
estáticas.
2 Metodología
Los aspectos a tomar en cuenta al usar el patrón de diseño Adapter en una aplicación web, son
hacer uso de clases existente y cuya interfaz no coincide, crear una clase reutilizable que coopere
con clases no relacionadas.
El objetivo de este patrón de diseño, es convertir la interfaz de una clase existente en la interfaz
esperada por los clientes, también existentes de modo que puedan trabajar de manera conjunta.
Según (DEBRAUWER, 2015, pág. 97)
Convierte la interfaz de una clase en otra interfaz que es la que esperan los clientes. Permite que
cooperen clases que de otra forma no podrían por tener interfaces incompatibles. Según
(GAMMA, 2002, pág. 131).
8
Figura 1 Estructura Patrón Adapter
9
Las características que siempre están presentes en el patrón de diseño adaptador son tres:
Objetivo (Target) que es la interfaz o la clase abstracta en donde se incluyen los métodos
objetivos que son los métodos que se quieren adecuar y son métodos abstractos. Otro
componente es el Adaptador (Adapter) que es el que sirve como puente entre la clase que se va
a adaptar y el Objetivo. Y el último componente es el Adaptable (Adaptee) que es el que contiene
métodos que no son completamente compatibles con el Objetivo (Target), si yo quisiera hacer
que el Adaptable herede del Objetivo no se podría hacer ya que este contiene métodos distintos.
Entonces lo que se hace es una agregación, para así hacer uso del Adaptable y adecuarlo según
los métodos del Adaptador.
Cuando se tiene que hacer que la aplicación web que se diseñó deba cumplir nuevas
funcionalidades para ello debe crear nuevas clases, el hecho de añadir nuevas clases
evidentemente puede hacerle modificar antiguas clases, porque ocasionara, cambios en su
diagrama, a lo que esto nos lleva, es a tener que eliminar esas ideas antiguas.
Por eso, este patrón nos ayuda a reutilizar, sabiendo que las clases nuevas y clases antiguas no
se pueden conectar, porque no tienen los mismos métodos, es ahí donde entra este patrón en el
cual se crea un adaptador y gracias a este adaptador podremos llamar a las clases antiguas y
nuevas de la misma manera.
Back End
Target (Objetivo)
10
public Clase1(){}
@Override
public void Peticion1()
{
}
@Override
public void Peticion2()
{
}
@Override
public void PeticionN()
{
}
}
Adaptee
@Override
public void PeticionPropia1()
{
}
@Override
public void PeticionPropia2()
{
}
11
@Override
public void PeticionPropiaN()
{
}
}
Adapter
public Clase2Adapter(){
this.clase2 = new Clase2();
}
@Override
public void Peticion1()
{
this.clase2.PeticionPropia1();
this.clase2.PeticionPropia2();
}
@Override
public void Peticion2()
{
this.clase2.PeticionPropia3();
}
@Override
public void PeticionN()
{
this.clase2.PeticionPropiaN();
12
}
}
Cliente
public class Client
{
public static void main( String[] args )
{
Client cliente = new Client();
client.Operacion1;
client.Operacion2;
}
private void Operacion1
{
Target target = new Clase1();
target. Peticion1();
target. Peticion2();
target. PeticionN();
}
private void Operacion2
{
Target target = new Clase2Adapter();
target. Peticion1();
target. Peticion2();
target. PeticionN();
}
}
Ejemplo
Target (Objetivo)
public abstract class Animal
{
abstract public void raza();
abstract public void tamano();
13
abstract public void peso();
abstract public void color();
}
@Override
public void raza()
{
}
@Override
public void tamano()
{
}
@Override
public void peso()
{
}
@Override
public void color()
{
}
}
14
public class Gato extends Animal
{
public Gato()
{
super();
}
@Override
public void raza()
{
}
@Override
public void tamano()
{
}
@Override
public void peso()
{
}
@Override
public void color()
{
}
}
Adapter
public class PajaroAdapter extends Animal
{
public Pajaro pajaro;
15
public PajaroAdapter()
{
super();
this.pajaro = new Pajaro();
}
@Override
public void raza()
{
this.pajaro.alas();
this.pajaro.pico();
this.pajaro.plumaje();
}
@Override
public void tamano()
{
}
@Override
public void peso()
{
}
@Override
public void color()
{
}
}
Adaptee
public class Pajaro
{
16
public Pajaro()
{
}
17
animal.tamano();
animal.peso();
animal.color();
}
Los aspectos a tomar en cuenta al usar el patrón de diseño Bridge en una aplicación web, son
evitar un enlace permanente entre una abstracción y su implementación, los cambios de una
implementación no deberían tener impacto en los clientes, permitir combinar diferentes
abstracciones y sus implementaciones, y extenderlas independientemente.
Desacopla una abstracción de su implementación, de modo que ambas puedan variar de forma
independiente. (GAMMA, 2002, pág. 141). Una abstracción se refiere a un comportamiento que
una clase debería implementar, con lo cual este patrón permite modificar las implementaciones
18
de una abstracción en tiempo de ejecución, de esta manera ambas pueden ser modificadas
independientemente sin necesidad de alterar por ella la otra.
Con este patrón se puede dividir un componente complejo en 2 jerarquías independientes, pero
relacionadas, las cuales serían la abstracción funcional y la implementación interna, esto hace
19
que sea más fácil cualquier aspecto del componente. La abstracción va a tener una relación con
la implementación, la implementación tiene la capacidad de realizar el almacenamiento de la
información, mientras que, la abstracción tiene la capacidad de representar esa información de
forma independiente. De esta manera el patrón de diseño nos ayuda a minimizar la generación
de código que se realiza para independizar la funcionalidad de la representación, esto hace que
se puedan mezclar y combinar diferentes clases de representaciones y comportamientos, esto
nos da una mucho mayor funcionalidad ya que estas combinaciones producen una gama más
amplia.
Back End
Implementor (Implementador)
ConcreteImplementor (ImplementadorConcreto)
@Override
public int OperacionImp_2(int item)
{
20
.
.
return ...;
}
@Override
public boolean OperacionImpl_3()
{
return true;
}
}
public class ImplementorConcret_2 implements Implementor
{
@Override
public void Operacion_1()
{
.
.
}
@Override
public int Operacion_2(int item)
{
.
return ...;
}
@Override
public boolean Operacion_3()
{
return true;
21
}
}
Abstraction (Abstracción)
RefinedAbstraction (AbstraccionRefinada)
public class AbstraccionRefinada_1() extends Abstraction
{
@Override
public int Operacion_2(int item)
{
.
.
return ...;
}
}
22
public class AbstraccionRefinada_2() extends Abstraction
{
@Override
public void Operacion_1()
{
.
.
}
}
Los aspectos a tomar en cuenta al usar el patrón de diseño Composite en una aplicación web,
son representar jerarquías de objetos, que los clientes sean capaces de obviar las diferencias
entre las composiciones de objetos y los objetos individuales.
Compone objetos en estructuras de árbol para representar jerarquías de parte-todo. Permite que
los clientes traten de manera uniforme a los objetos individuales a los compuestos (GAMMA,
2002, pág. 151).
Este patrón de diseño ofrece un marco de diseño de una composición de objetos de profundidad
variable, diseño que estará basado en árbol. Esta composición esta encapsulada con respecto a
los clientes de los objetos que pueden interactuar, sin tener que conocer la profundidad de la
composición. (DEBRAUWER, 2015, pág. 119).
23
Figura 4 Estructura Patrón Composite
Este patrón nos permite crear una estructura compleja a partir de una estructura más simple, la
cual puede funcionar por si sola como un sistema.
Se debe identificar los tres roles que se manejan en este patrón, tales como el rol de
Componente, el rol de Compuesto y el rol de Hoja, buscando nombres apropiados y eligiendo
bien el rol que desempeña. El Componente es el que ven los clientes, este debe llevar los
atributos comunes de hoja y compuesto, luego se añade los métodos. El rol Hoja lleva los
atributos de cada hoja. El rol Compuesto lleva los atributos del compuesto respetando las
relaciones.
24
Back End
Componente
public abstract class Componente
{
private String name;
Compuesto
public class Compuesto extends Componente
{
private java.util.List<Componente> list;
25
this.list = new java.util.ArrayList<>();
}
@Override
public String view(String head)
{
StringBuilder result = new StringBuilder();
result.append(head + "-" + this.getName() + ":" + "\n");
for (Component item : list)
{
result.append(item.view(head + " "));
}
return result.toString();
}
@Override
public void add(Componente cc)
{
list.add(cc);
}
@Override
public void remove(Componente cc)
{
list.remove(cc);
}
@Override
public boolean isCompuesto()
{
return true;
}
26
@Override
public String toString()
{
return "C:" + this.getName().toLowerCase();
}
}
Hoja
public class Hoja extends Componente {
@Override
public String view(String cabecera) {
return cabecera + "-" + this.toString() + "\n";
}
@Override
public String toString() {
return "H1:" + this.getName().toLowerCase();
}
@Override
public void remove(Componente cc) {
throw new UnsupportedOperationException("Operacion no soportada");
}
@Override
public void add(Componente cc) {
27
throw new UnsupportedOperationException("Operacion no soportada");
}
@Override
public boolean isCompuesto() {
return false;
}
}
Los aspectos a tomar en cuenta al usar el patrón de diseño Decorador en una aplicación web,
son para añadir objetos individuales de forma dinámica y transparente, es decir sin afectar a otros
objetos, cuando la extensión mediante la herencia no es viable.
Este patrón nos permite modificar dinámicamente el comportamiento de un objeto. Puede ser
considerado como una alternativa a declarar una clase que hereda de otra. (MONTORO, 2012,
pág. 111).
28
Figura 5 Estructura Patrón Decorador
Componente: Define la interfaz para objetos a los que se puede añadir responsabilidades
dinámicamente.
Componente Concreto: Define un objeto al que se pueden añadir responsabilidades
adicionales.
Decorador: Mantiene una referencia a un objeto Componente y define una interfaz que
se ajusta a la interfaz del componente.
Decorador Concreto: Añade responsabilidades al componente.
29
Back End
Componente
public abstract class Componente{
abstract public void operacion();
}
Componente Concreto
public class ComponenteConcreto extends Componente{
public void operacion(){
System.out.println("ComponenteConcreto.operacion()");
}
}
Decorador
public abstract class Decorador extends Componente{
private Componente componente;
Decorador Concreto A
public class DecoradorConcretoA extends Decorador{
private String propiedadAñadida;
30
}
Decorador Concreto B
public class DecoradorConcretoB extends Decorador{
public DecoradorConcretoB(Componente componente){
super(componente);
}
Los aspectos a tomar en cuenta al usar el patrón de diseño Fachada en una aplicación web, son
proporcionar una interfaz simple para un subsistema complejo, que haya muchas dependencias
entre los clientes y las clases que implementan una abstracción, dividir en capas nuestros
subsistemas.
31
Proporciona una interfaz unificada para un conjunto de interfaces de un subsistema. Define una
interfaz de alto nivel que hace que el subsistema sea más fácil de usar (GAMMA, 2002, pág.
171).
Este patrón eleva el nivel de abstracción de un determinado sistema para ocultar ciertos detalles
de implementación y hacer más sencillo el uso (MONTORO, 2012, pág. 131)
32
Figura 7 Sin y Usando el patrón Fachada
Facade (Fachada): Sabe que clases del subsistema son las responsables ante una
petición. Delega las peticiones de los clientes en los objetos apropiados del subsistema.
Clases del subsistema: Implementan la funcionalidad del subsistema. Realizan las
labores encomendadas por el objeto Fachada. No tiene referencias a la Fachada.
Este patrón de diseño se encarga de simplificarle los procesos al cliente, haciendo que el cliente
se desentienda de toda la complejidad del sistema permitiendo realizar acciones cortas para
ejecutar procesos complejos
33
Back End
Subsistemas
public class X
{
public void m7() {
System.out.println("m7 de X");
}
}
public class Y {
public void m8() {
System.out.println("m8 de Y");
}
}
public class A {
public void m1() {
System.out.println("m1 de A");
}
public void m2() {
System.out.println("m2 de A");
}
}
public class B {
public void m3() {
System.out.println("m3 de B");
}
public void m4(A a) {
System.out.println("m4 de B");
}
}
public class C {
public void m5() {
34
System.out.println("m5 de C");
}
}
public class D {
public void m6(D d) {
System.out.println("m6 de D");
}
}
Fachada
public class SubsystemFacade {
private A a;
private B b;
private C c;
private D d;
public SubsystemFacade() {
a = new A();
b = new B();
c = new C();
d = new D();
}
35
}
Cliente
public class Client
{
public void exec(){
SubsystemFacade subsystemFacade = new SubsystemFacade();
subsystemFacade.m1_2();
subsystemFacade.m3_4();
subsystemFacade.m5();
subsystemFacade.m6();
//...
X x = new X();
x.m7();
//...
Y y = new Y();
y.m8();
}
}
36
3.6 Aspectos a tomar en cuenta al usar el Patrón de diseño Flyweight o Peso
Ligero
Los aspectos a tomar en cuenta al usar el patrón de diseño Peso Ligero en una aplicación web,
son cuando una aplicación utiliza un gran número de objetos, costes de almacenamientos
elevados debido a la cantidad de objetos, muchos grupos de objetos pueden reemplazarse por
objetos compartidos y la aplicación no depende de la identidad de un objeto.
El patrón de diseño Peso Ligero usa un comportamiento para permitir un gran número de
objetos de grano fino de forma eficiente (GAMMA, 2002, pág. 179).
El patrón Peso Ligero permite compartir un objeto entre los clientes, creando una responsabilidad
para el objeto compartido que los objetos normales no necesitan considerar. Un objeto ordinario
no tiene que preocuparse mucho por la responsabilidad compartida. Muy a menudo, solo un
cliente tendrá una referencia de un objeto en cualquier momento. Cuando el cambio de estado
del objeto se debe a que el cliente lo cambió, y el objeto no tiene ninguna responsabilidad de
informar a otros clientes. A veces, sin embargo, querrá hacer arreglos para que varios clientes
compartan el acceso a un objeto (METSKER, 2006, pág. 145).
37
Según la Figura 8 los componentes de este patrón son:
Flyweight (PesoLigero): Declara una interfaz a través de la cual los pesos ligeros pueden
recibir un estado extrinseco y actuar sobre él.
ConcreteFlyweight (PesoLigeroConcreto): Implementa la interfaz PesoLigero y permite
almacenar el estado intrínseco, en caso de que lo haya. Un objeto PesoLigeroConcreto
debe poder ser compartido, por lo que cualquier estado que almacene debe ser
intrínseco, esto debe ser independiente del contexto del objeto PesoLigeroConcreto.
UnsharedConcreteFlyweight (PesoLigeroConcretoNoCompartido): No todas las clases
de PesoLigero necesitan ser compartidas. La interfaz PesoLigero permite el
comportamiento, no fuerza a él. Los objetos PesoLigeroConcretoNoCompartido suelen
tener objetos PesoLigeroConcreto como hijos en algún nivel de la estructura de objetos
(como es el caso de filas y columnas).
FlyweightFactory (FabricaPesosLigeros): Crea y controla objetos pesos Ligeros.
Garantiza que los pesos ligeros se compartan de manera adecuada. Cuando un cliente
solicita un peso Ligero, el objeto FabricaPesosLigeros proporciona una instancia concreta
o crea uno nuevo, en caso de que no exista ninguno.
Client (Cliente): Mantiene una referencia de los pesos ligeros. Calcula o guarda el estado
extrínseco de los pesos ligeros.
Back End
Peso Ligero
public interface PesoLigero
{
public String Operacion();
}
Peso Ligero Concreto
public class PesoLigeroConcreto implements PesoLigero
{
public String parm;
public PesoLigeroConcreto(String parm){
this.parm = parm;
38
}
@Override
public String Operacion()
{
return "Patente: " + this.parm;
}
}
Los aspectos a tomar en cuenta al usar el patrón de diseño Proxy en una aplicación web, son la
necesidad de una referencia a un objeto más versátil o sofisticada que un simple puntero, cuando
queremos controlar el acceso a un componente de esta forma no tenemos que crear objetos
costosos que no serán utilizados, controlar los derechos de acceso a un objeto, gestionar
accesos múltiples de clientes a un recurso.
Proporciona un representante o sustituto de otro objeto para controlar el acceso a éste. (GAMMA,
2002, pág. 191)
39
El patrón Proxy nos da una solución para una tarea de programación muy común. Un proxy es
una clase que representa y proporciona acceso a otro objeto. Este otro objeto no siempre es un
objeto de ActionScript. Podría ser un archivo de imagen, un archivo XML, un servicio Flash
Remoting o un servicio web. (LOTT, 2007, pág. 83)
Proxy: Mantiene una referencia que permite al proxy acceder al objeto real. El proxy
puede referirse a un Sujeto en caso de que las interfaces de SujetoReal y Sujeto sean la
misma. Proporciona una interfaz idéntica a la de Sujeto, de manera que un proxy pueda
ser sustituido por el SujetoReal. Controla el acceso al SujetoReal y puede ser responsable
de su creación y borrado.
Subject (Sujeto): Define la interfaz común para el SujetoReal y el proxy, de modo que
pueda usarse un Proxy en cualquier sitio en el que se espere un SujetoReal.
RealSubject (SujetoReal): Define un objeto real Representado.
40
El patrón de diseño proxy proporciona un objeto intermediario entre el cliente y el objeto a utilizar,
permite configurar ciertas características (como el acceso) sin necesidad de modificar la clase
original. Según la funcionalidad requerida se encuentran varios tipos de proxy, Proxy Remoto
representa un objeto de otro espacio de direcciones, Proxy Virtual retrasa la creación de objetos
costosos, Proxy de protección controla el acceso de un objeto.
Se crea un interfaz Sujeto que define toda la funcionalidad que nuestro objeto a de proveer, esta
interfaz debe ser implementada por el Sujeto Real, crearemos un objeto proxy que mantendrá
una referencia al Sujeto Real y que además implementara la interfaz Sujeto de modo que a la
hora de precisar la funcionalidad sea diferente si se está ejecutando el proxy o el Sujeto Real.
Back End
Sujeto
public interface Subject
{
public void doService();
}
Real Sujeto
public class RealSubject implements Subject
{
@Override
public void doService()
{
System.out.println("Real Subject doing service...");
}
}
Proxy
public class Proxy implements Subject
{
private Subject wrapee;
41
public Proxy(Subject wrapee)
{
this.wrapee = wrapee;
}
@Override
public void doService()
{
anotherFunctionality();
if(wrapee == null)
{
wrapee = new RealSubject(); //Just for this pattern example
}
wrapee.doService();
}
private void anotherFunctionality()
{
System.out.println("Doing another functionality from Proxy...");
}
}
42
4 Conclusiones
Se mencionó que los diferentes patrones de diseño estructurales se usan según al tipo de
aplicación o necesidad que se tenga al desarrollar una aplicación Web.
Los aspectos a tomar en cuenta al momento de usar el patrón de diseño Adapter en una
aplicación web, son hacer uso de clases existente y cuya interfaz no coincide, crear una clase
reutilizable que coopere con clases no relacionadas.
Los aspectos a tomar en cuenta al usar el patrón de diseño Bridge en una aplicación web, son
evitar un enlace permanente entre una abstracción y su implementación, los cambios de una
implementación no deberían tener impacto en los clientes, permitir combinar diferentes
abstracciones y sus implementaciones, y extenderlas independientemente.
Los aspectos a tomar en cuenta al usar el patrón de diseño Composite en una aplicación web,
son representar jerarquías de objetos, que los clientes sean capaces de obviar las diferencias
entre las composiciones de objetos y los objetos individuales.
Los aspectos a tomar en cuenta al usar el patrón de diseño Decorador en una aplicación web,
son para añadir objetos individuales de forma dinámica y transparente, es decir sin afectar a otros
objetos, cuando la extensión mediante la herencia no es viable.
Los aspectos a tomar en cuenta al usar el patrón de diseño Fachada en una aplicación web, son
proporcionar una interfaz simple para un subsistema complejo, que haya muchas dependencias
entre los clientes y las clases que implementan una abstracción, dividir en capas nuestros
subsistemas.
43
Los aspectos a tomar en cuenta al usar el patrón de diseño Peso Ligero en una aplicación web,
son cuando una aplicación utiliza un gran número de objetos, costes de almacenamientos
elevados debido a la cantidad de objetos, muchos grupos de objetos pueden reemplazarse por
objetos compartidos y la aplicación no depende de la identidad de un objeto.
Los aspectos a tomar en cuenta al usar el patrón de diseño Proxy en una aplicación web, son la
necesidad de una referencia a un objeto más versátil o sofisticada que un simple puntero, cuando
queremos controlar el acceso a un componente de esta forma no tenemos que crear objetos
costosos que no serán utilizados, controlar los derechos de acceso a un objeto, gestionar
accesos múltiples de clientes a un recurso.
44
5. Bibliografía
Addison-Wesley.
https://www.researchgate.net/publication/262439445_Patrones_de_Diseno_GOF_The_G
ang_of_Four_en_el_contexto_de_Procesos_de_Desarrollo_de_Aplicaciones_Orientadas_
a_la_Web
45