Está en la página 1de 80

UNIVERSIDAD NACIONAL DEL SANTA

FACULTAD DE INGENIERÍA

ESCUELA DE INGENIERÍA DE SISTEMAS E INFORMÁTICA

PATRONES DE DISEÑO
DE SOFTWARE

Manual de Aprendizaje teórico práctico

Ms. Yim Isaias Apestegui Florentino

Nuevo Chimbote, Perú

Abril 2019
2
Acerca del autor

3
Requisitos previos
Este manual está pensado para estudiantes de la carrera de ingeniería de sistemas
e informática y afines programadores junior que se inician en la carrera como
programadores de software o para programadores senior que desean aplicar
conocimientos de patrones de diseño.

De manera que se necesita conocimientos básicos de programación orientada a


objetos y conocimientos de UML, básicamente de los diagramas de clases y de
secuencia a fin de entender mejor cada patrón.

4
5
Contenido
Sesión 1.......................................................................................................... 8

1.- Introducción a los Patrones de Diseño de Software ................................... 8

Un poco de historia .................................................................................... 8

Objetivos de los patrones.......................................................................... 11

Categorías de patrones.............................................................................. 11

Estructuras o plantillas de patrones........................................................... 12

Sesión 2........................................................................................................ 14

Comprensión de las clases y los objetos ....................................................... 14

Objetos ..................................................................................................... 14

Atributos .................................................................................................. 14

Mensajes. ................................................................................................. 15

Características de un mensaje. .............................................................. 15

Otros métodos que puede realizar laMototaxi ....................................... 15

Las Clases ................................................................................................ 16

Definición de una clase en Java ............................................................ 17

Estado del objeto ...................................................................................... 18

Relaciones entre clases ................................................................................. 19

R1: Relación de Herencia (Generalización / Especialización o Es-un) ..... 20

R2:Relación de Agregación (Todo / Parte, Forma parte de)...................... 21

R3:Relación de Composición ................................................................... 22

R4: Relación de Asociación («uso», usa, cualquier otra relación)............. 23

Encapsulamiento ...................................................................................... 24

Vamos a ver un ejemplo: ...................................................................... 24

Ejercicios ..................................................................................................... 26

6
El Patrón Abstract Factory ( ......................................................................... 29

Problema .................................................................................................. 29

Discusión ................................................................................................. 29

Ejemplo de un Sistema de Venta de Vehículos ......................................... 30

SOLUCIÓN ......................................................................................... 31

Estructura del Patrón Fábrica de Abstracciones ........................................ 32

1.-Diagrama de clases ........................................................................... 32

2.-Participantes. .................................................................................... 32

3.- Colaboraciones ................................................................................ 33

Dominios de uso....................................................................................... 33

Ejercicio propuesto....................................................................................... 39

7
Sesión 1

1.- Introducción a los Patrones de Diseño de


Software
Un patrón de diseño es una abstracción de una solución. Los patrones tratan de
solucionar problemas que existen en muchos niveles de abstracción. Los
patrones pueden estar inmersas en las distintas etapas del desarrollo; partiendo
del análisis al diseño y desde la arquitectura hasta la implementación.

Un poco de historia
Por los años 1994, se publica el libro "Design Patterns: Elements of Reusable
Object Oriented Sofware" escrito por los 4 amigos Gang of Four (GoF), que en
español es la pandilla de los cuatro, formada por Erich Gamma, Richard Helm,

8
Ralph Johnson y John Vlissides. Ellos recopilaron y documentaron 23 patrones
de diseño aplicados usualmente por expertos diseñadores de software orientado
a objetos.

Según el libro de Erich Gamma, Design Patterns: Elements of Reusable


Object-Oriented Software, un Patrón de Diseño es "una solución simple y
elegante a un problema específico y común del Diseño Orientado a Objetos
(DOO)". Indicando que: "son soluciones basadas en la experiencia y cuya
fiabilidad está demostrada".

Los patrones de diseño son la base para la búsqueda de soluciones a problemas


comunes o problemas recurrentes en el desarrollo de software y otros ámbitos
referentes al diseño de interacción o interfaces.

Un patrón de diseño resulta ser una solución a un problema de diseño.


¿Problemas de diseño? ¡Claro! Imagínese que Ud. tiene que construir un
edificio, posiblemente tendrá que preguntarse por
las características de dicho edificio: Cómo debe
apreciarse por dentro y fuera del mismo, cómo es
su estructura, qué tanto debe soportar dichas
estructuras, cómo debe interaccionar con su
entorno.

9
De manera similar, si Ud. construye un sistema, debe saber por dónde empezar,
qué características debe tener dicho sistema, cómo interactúa con su entorno.
Y si dicho sistema necesita software, pues
debe saber qué se espera de dicho
software, como es su comportamiento,
cómo son sus interfaces, qué problemas
soluciona dicho software, y como se
adapta a nuevos componentes, etc.

De manera que, en la ingeniería, siempre tendremos problemas de diseño.

De hecho, que los problemas de diseño no son nuevos; tienen precedentes,


alguien ya se enfrentó a dichos problemas y los han tipificado, estudiado y
mejorado de tal manera que se han convertido en modelos base de solución,
que lo llamaremos patrones de diseño.

Los patrones de diseño han sido optimizados, son soluciones reutilizables a los
problemas de programación. Un patrón de diseño no es una clase o una
biblioteca que, simplemente, puede conectarse a nuestro sistema, es mucho más
que eso.

Es una plantilla que tiene que aplicarse a la situación correcta. Tampoco es


específica de un lenguaje. Un buen patrón de diseño debe poder aplicarse en la
mayoría de los lenguajes de programación.

Algunos autores mencionan que, cualquier patrón de diseño puede ser un arma
de doble filo, si se aplican en el lugar equivocado, puede ser desastroso y crear
muchos problemas mayores. Sin embargo, si se implementa en el lugar correcto
y en el momento adecuado, puede ser de gran ayuda.

De manera que para que una solución sea considerada un patrón debe poseer
ciertas características. Una de ellas es que debe haber comprobado su

10
efectividad resolviendo problemas similares en ocasiones anteriores. Otra es
que debe ser reutilizable, lo que significa que es aplicable a diferentes
problemas de diseño en distintas circunstancias.

Objetivos de los patrones

Los patrones de diseño pretenden:

 Proporcionar catálogos de elementos reusables en el diseño de sistemas


software.
 Evitar la reiteración en la búsqueda de soluciones a problemas ya
conocidos y solucionados anteriormente.
 Formalizar un vocabulario común entre diseñadores.
 Estandarizar el modo en que se realiza el diseño.
 Facilitar el aprendizaje de las nuevas generaciones de diseñadores
condensando conocimiento ya existente.

Asimismo, no pretenden:

 Imponer ciertas alternativas de diseño frente a otras.


 Eliminar la creatividad inherente al proceso de diseño.

No es obligatorio utilizar los patrones, solo es aconsejable en el caso de tener


el mismo problema o similar que soluciona el patrón, siempre teniendo en
cuenta que en un caso particular puede no ser aplicable. “Abusar o forzar el uso
de los patrones puede ser un error”.

Categorías de patrones

Según la escala o nivel de abstracción:

 Patrones de arquitectura: Aquellos que expresan un esquema


organizativo estructural fundamental para sistemas de software.

11
 Patrones de diseño: Aquellos que expresan esquemas para definir
estructuras de diseño (o sus relaciones) con las que construir sistemas de
software.

 Dialectos: Patrones de bajo nivel específicos para un lenguaje de


programación o entorno concreto.

Además, también es importante reseñar el concepto de “antipatrón de diseño”,


que con forma semejante a la de un patrón, intenta prevenir contra errores
comunes de diseño en el software. La idea de los antipatrones es dar a conocer
los problemas que acarrean ciertos diseños muy frecuentes, para intentar evitar
que diferentes sistemas acaben una y otra vez en el mismo callejón sin salida
por haber cometido los mismos errores.

Además de los patrones ya vistos actualmente existen otros patrones como el


siguiente:

 Interacción: Son patrones que nos permiten el diseño de interfaces web.

Estructuras o plantillas de patrones

Para describir un patrón se usan plantillas más o menos estandarizadas, de


forma que se expresen uniformemente y puedan constituir efectivamente un
medio de comunicación uniforme entre diseñadores. Varios autores eminentes
en esta área han propuesto plantillas ligeramente distintas, si bien la mayoría
definen los mismos conceptos básicos.

La plantilla más común es la utilizada precisamente por el GoF y consta de los


siguientes apartados:

 Nombre del patrón: nombre estándar del patrón por el cual será
reconocido en la comunidad (normalmente se expresan en inglés).
12
 Clasificación del patrón: creacional, estructural o de comportamiento.
 Intención: ¿Qué problema pretende resolver el patrón? También
conocido como: Otros nombres de uso común para el patrón.
 Motivación: Escenario de ejemplo para la aplicación del patrón.
 Aplicabilidad: Usos comunes y criterios de aplicabilidad del patrón.
 Estructura: Diagramas de clases oportunos para describir las clases que
intervienen en el patrón.
 Participantes: Enumeración y descripción de las entidades abstractas (y
sus roles) que participan en el patrón.
 Colaboraciones: Explicación de las interrelaciones que se dan entre los
participantes.
 Consecuencias: Consecuencias positivas y negativas en el diseño
derivadas de la aplicación del patrón.
 Implementación: Técnicas o comentarios oportunos de cara a la
implementación del patrón.
 Código de ejemplo: Código fuente ejemplo de implementación del
patrón.
 Usos conocidos: Ejemplos de sistemas reales que usan el patrón.
 Patrones relacionados: Referencias cruzadas con otros patrones.

Fuentes:

https://ittgweb.wordpress.com/2016/05/29/3-2-patrones-de-diseno/

http://www.ciberaula.com/articulo/diseno_patrones_j2ee

13
Sesión 2

Comprensión de las clases y los objetos


Objetos
Los Objetos son o representan cosas, podría decir Cosas Físicas o abstractas.

Los objetos pueden ser tan simples como por ejemplo una mesa, o tan compleja
como un motor. De manera que los objetos pueden ser reales, tangibles como
intangibles o hasta imaginarios, por ejemplo, el objeto “sentimientos” que solo
podemos caracterizar o definirlo por sus atributos tipo de sentimiento.

Así tenemos ejemplos de objetos: Una varilla de fierro, filete de pescado,


conservas de espárragos, objetos producidos en la Provincia del Santa (Perú),
así como una Red de Datos, un automóvil, una empresa, un “Hola Mundo”.

Atributos
Para nosotros serán representación de los valores o características de los
objetos, los cuales nos permite definir sus cualidades inclusive hasta su estado
(término que veremos más adelante).

Así si pensamos en un mototaxi.

14
Podemos definir que existen Características Variables, como:

 La velocidad; que varía desde el arranque


 La aceleración: que varía entre cambios de velocidades.
 Clima: sensación de la temperatura dentro del vehículo.
 Capacidad de Combustible: De acuerdo a cuánto se llena en el grifo.

Así mismo, podemos definir Características Constantes, como:

 Modelo
 Marca
 Color
 Serie de motor
 Velocidad Tope
 Capacidad máxima de pasajeros.
 Número de llantas.

Mensajes.
Los objetos, para nuestro estudio deben tener la capacidad de comunicarse por
medio de mensajes. Claro está que los mensajes deben tener el dato, o
información necesaria que el otro objeto espera. Si un objeto desea que otro
objeto realice una operación o realice algo, el primero debe enviarle un mensaje

En adelante estas operaciones a realizar se conocerán como métodos, un objeto


debe realizar un método frente a un mensaje de otro objeto.

Características de un mensaje.
 Objeto destino del mensaje enviado. laMototatxi
 Método a ejecutarse. encenderMotor
 Parámetros del método. contactoenON

Otros métodos que puede realizar laMototaxi


 Encender Motor

15
 Apagar Motor
 Acelerar
 Frenar
 Avanzar hacia adelante
 Retroceder (sólo algunas motos).
 Girar a la derecha
 Girar a la izquierda
 Realizar cambios (tipo cambio)

Para nuestro caso Realizar Cambios (tipo cambio): “Realizar Cambios”


corresponde al nombre del Método, “tipo cambio”, pertenece a los
parámetros requeridos. En la bibliografía también a los parámetros se le
conoce como argumentos. Por ello se suele decir en programación: “… qué
tipo de argumento o tipo de parámetros se está pasando al método…”.

Los métodos suelen devolver valores de retorno generalmente, pero a veces


no devuelven valores y sólo realizan una determinada operación.

Las Clases
Representan un tipo especial o particular de una colección de objetos, que
pueden tener características similares inclusive comportamiento, pero que no
representa un concepto más general que el de un objeto.

16
Así podríamos tener una clase Mototaxis, o una clase más genérica llamada
clase automóvil o más aún una clase Vehículo. Y cada clase podría tener toda
una variedad de objetos.

Entonces hacer POO(Programación Orientada a Objetos), es escribir el


código que corresponde a cada clase con sus atributos, métodos y los mensajes
correspondientes.

Ejemplo:

Definición de una clase en Java


class vehiculo {

// atributos:
String modelo;
String marca;
String color;
double velocidad_tope;
String tipo_gasolina;
double velocidad;
double aceleracion;

// métodos:
void encender() {
// instrucciones para encender
};
void partida() {
// instrucciones para la partida del vehículo
};

void frenar() {
// instrucciones para frenar el vehículo
};

17
void acelerar() {
// instrucciones para acelerar el vehículo
};
void girar_derecha(int grados) {
// instrucciones para girar a la derecha
};
// Así se pueden añadir otros métodos
}; // fin definición de la clase vehículo

Estado del objeto

Bien, ahora sí estamos en ya en la capacidad de entender que de cada clase


podemos crear otros objetos o múltiples objetos, donde cada objeto tiene sus
atributos con valores específicos o propios. Esa instantánea en la que los
atributos del objeto toman valores específicos se conoce como estado del
objeto.

empleado1:Empleado
NOMBRE apellido=”Zamudio”
nombre=”Danton” ESTADO INTERNO
sexo=”masculino”
sueldo=”2000.00”
calcularSueldo()
INTERFACE calcularAñosServicio()

En el ejemplo empleado1 sería un objeto que pertenece a la clase Empleado

Todos los objetos con el mismo estado interno, y las mismas interfaces se
agrupan en una sola clase.

18
La representación de los diagramas de clases en UML, es a través de un
rectángulo denominado clasificador. Un clasificador nos indica el nombre de
la clase y un ejemplo de dicha clase será un objeto. Las clases tienen
características que comprenden a los atributos y los comportamientos
(métodos).

Cuando empiece a captar clases en sus modelos, abstraiga


de modo conceptual como una fase inicial, basta empezar
solamente con clases y relaciones. Las características se
agregan más adelante (Kimmel, 2008).

Relaciones entre clases


Como paradigma las clases se construyen para que trabajen de manera
relacionada, compartiendo atributos y métodos y sobre todo, evitando la
reescritura de código.

Precisamente las jerarquías entre clases permiten extender y reutilizar código,


así tenemos:

 R1:Herencia (Generalización / Especialización o Es-un)


 R2:Agregación (Todo / Parte o Forma-parte-de)
 R3:Composición (Es parte elemental de)
 R4:Asociación (entre otras, la relación Usa-a)

19
R1: Relación de Herencia (Generalización / Especialización o Es-
un)
Es un tipo de jerarquía de clases, donde cada subclase contiene los atributos y
métodos de una (herencia simple) o más superclases (herencia múltiple).

Vehiculo.java Automovil.java Camion.java


package model; package model; package model;

public class Vehiculo public class public class Camion


{ Automovil extends extends Vehiculo
Vehiculo {
{
public Vehiculo(){ public Automovil(){ public Camion(){
super(); super(); super();
} } }

} } }

20
R2:Relación de Agregación (Todo / Parte, Forma parte de)
Este tipo de relación representa a los objetos compuestos por otros objetos.

El objeto en el nivel superior de la jerarquía es el todo y los que están en los


niveles inferiores son sus partes o componentes.

Vehiculo.java Motor.java
package model; package model;

public class Vehiculo public class Motor


{ {

public Vehiculo vehiculo;


public Motor motor;

public Motor(){
public Vehiculo(){ super();
super(); }
}
}
}

21
R3:Relación de Composición
Un componente es parte esencial de un elemento. Si el componente es
eliminado o desaparece, la clase mayor deja de existir.

Persona.java Cabeza.java

package model; package model;


import java.util.HashSet;
import java.util.Set;
public class Persona
{
public class Cabeza
{
public Cabeza cabeza;
public Set<Persona> persona;

public Persona(){ public Cabeza(){


super(); super();
} }

} }

22
R4: Relación de Asociación («uso», usa, cualquier otra relación)
La relación de asociación se establece cuando dos clases tienen una
dependencia de uso es decir, una clase usa atributos y/o métodos de otra para
funcionar.

Cliente.java Compra.java

package model; package model;


import java.util.HashSet;
import java.util.Set;
public class Compra
{
public class Cliente
{ public Cliente cliente;

public Set<Compra> compra;


public Compra(){
super();
public Cliente(){ }
super();
} }

23
Encapsulamiento
Los objetos muestran hacia afuera la interface, pero ocultan la implementación
y el estado interno.

Existen tres niveles de acceso para el encapsulamiento, los cuales son:


Público (Public): Todos pueden acceder a los datos o métodos de una clase
que se definen con este nivel, este es el nivel más bajo, esto es lo que deseamos:
que la parte externa vea.

Protegido (Protected): Podemos decir que no son de acceso público,


solamente son accesibles dentro de su clase y por subclases.

Privado (Private): En este nivel se puede declarar miembros accesibles sólo


para la propia clase.

Vamos a ver un ejemplo:

El Ejemplo del Vehículo nuevamente, donde se tiene la característica COLOR.

CASO 1: Se necesita que cualquiera pueda acceder al color de un vehículo,


entonces:

Opción a: Declaro entonces COLOR como Privado

Opción b: Declaro entonces COLOR como Protegido

Opción c: Declaro entonces COLOR Como Público

CASO 2: Se necesita qué color se pueda acceder a través no sólo de vehículo, sí


no ahora también a través de Camión (que es un tipo de vehículo), entonces
también se debe tener acceso a color.

Opción a: Declaro entonces COLOR como Privado

Opción b: Declaro entonces COLOR como Protegido

Opción c: Declaro entonces COLOR Como Público

24
CASO 3: Se requiere acceder a color, solamente para vehículo.

Opción a: Declaro entonces COLOR como Privado

Opción b: Declaro entonces COLOR como Protegido

Opción c: Declaro entonces COLOR Como Público

25
Ejercicios
1.-Diseñe objetos:

a).-Defina el nombre del objeto, b) Establezca cinco atributos y c) Defina 2


métodos para los siguientes objetos: rectángulo, círculo, silla, mesa,
refrigerador, ventilador, televisor, casa, aula, plancha, puerta, ventana, camión,
bicicleta, barco, grifo, taza, amor, miedo, paciencia, carta pájaro, oveja, perro,
abeja, libro, cuchara, billete, nieve, azúcar, leche, pan, rosa, flor, queso,
panadero, abrelatas, sacapuntas, limpiavidrios, venta, compra, contrato,
matricula, recibo, motor. Diseñe 2 estados internos para cada objeto.

2.- Interprete los siguientes diseños, distinga qué tipo de relación corresponde
y codifique en java.

a)

b)

26
c)

3.- Diseñar el modelo siguiente:

a) Cada aula alberga uno o más grupos a los que se imparten una o más
asignaturas, a su vez cada grupo tiene asignada una o más aulas en donde recibe
docencia de una o más asignaturas, y además cada asignatura se imparte en una
o más aulas a uno o más grupos.

b) Diseñar un diagrama de clases que modele el proceso de dar de alta a cada


una de las personas que se apuntan a una asociación. De cada persona interesa
saber sus datos básicos: RUC, nombre completo y fecha de nacimiento. Cuando
cada nuevo socio se da de alta, se le asigna un código de asociado alfanumérico
y se anota la fecha de alta. La clase Fecha se modela con tres campos (día, mes
y año) de tipo entero. La clase RUC se modela con un campo de tipo entero
llamado dni y un campo de tipo carácter llamado letra.

c) Diseñar un diagrama de clases que modele la estructura necesaria para


manejar los datos de los encuentros de un torneo de tenis de mesa en la
modalidad de sorteo y eliminatoria.

27
Del torneo interesa conocer la fecha del torneo, los encuentros celebrados y el
ganador. De cada jugador, que debe de conocer perfectamente las reglas,
interesa saber el número de federado de la federación de la que es miembro.

De cada persona interesa saber sus datos básicos: RUC, nombre completo y
fecha de nacimiento. La clase Fecha se modela con tres campos (día, mes y
año) de tipo entero. La clase RUC se modela con un campo de tipo entero
llamado dni y un campo de tipo carácter llamado letra.

De cada encuentro interesa conocer los oponentes, el ganador y el resultado


final del marcador de cada una de las tres partidas que se juegan a 21 puntos.

https://slideplayer.es/slide/3965899/
https://styde.net/encapsulamiento-en-la-programacion-orientada-a-objetos/

28
Sesión 3

El Patrón Abstract Factory


El objetivo del patrón Abstract Factory es la creación de objetos agrupados en
familias sin tener que conocer las clases concretas destinadas a la creación de
estos objetos.

Problema
Si una aplicación debe ser portátil, esta debe encapsular las dependencias de la
plataforma. Estas "plataformas" pueden ser: sistema de ventanas, sistema
operativo, base de datos, etc. Muy a menudo, esta encapsulación no está
diseñada de antemano, y muchas declaraciones con diversas opciones para
todas las plataformas comienzan a aparecer esparcidos por todo el código
(SourceMaking, 2019).

Discusión
Se desea proporcionar un nivel de direccionamiento indirecto que resuma la
creación de familias de objetos relacionados o dependientes sin especificar
directamente sus clases concretas.

El “objeto fábrica" tiene la responsabilidad de proporcionar servicios de


creación para toda la familia de plataformas. Los clientes nunca crean objetos
de plataforma directamente, le piden a la fábrica que haga eso por ellos.

Este mecanismo facilita el intercambio de familias de productos porque la clase

específica del “objeto fábrica” aparece solo una vez en la aplicación, donde se

crea una instancia.

La aplicación puede reemplazar al por mayor toda la familia de productos


simplemente mediante la instanciación de una instancia concreta diferente de
la fábrica abstracta.
29
Ejemplo de un Sistema de Venta de Vehículos

Venta de vehículos, tomado de (Debrauwer, 2013).

El sistema de venta de vehículos gestiona vehículos que funcionan con gasolina


y vehículos eléctricos. Esta gestión está delegada en el objeto Catálogo
encargado de crear tales objetos.

Para cada producto, disponemos de una clase abstracta, de una subclase


concreta derivando una versión del producto que funciona con gasolina y de
una subclase concreta derivando una versión del producto que funciona con
electricidad.

Para el objeto Scooter, existe una clase abstracta Scooter y dos


subclases concretas ScooterElectricidad y ScooterGasolina.

El objeto Catálogo puede utilizar estas subclases concretas para instanciar los
productos.
30
No obstante si fuera necesario incluir nuevas clases de familias de vehículos
(diésel o mixto gasolina-eléctrico), las modificaciones a realizar en el objeto
Catálogo pueden ser bastante pesadas.

SOLUCIÓN
El patrón Abstract Factory resuelve este problema introduciendo una interfaz
FábricaVehículo que contiene la firma de los métodos para definir cada
producto. El tipo devuelto por estos métodos está constituido por una de las
clases abstractas del producto. De este modo el objeto Catálogo no necesita
conocer las subclases concretas y permanece desacoplado de las familias de
producto. Se incluye una subclase de implementación de FábricaVehículo por
cada familia de producto, a saber las subclases FábricaVehículoElectricidad y
FábricaVehículoGasolina. Dicha subclase implementa las operaciones de
creación del vehículo apropiado para la familia a la que está asociada.
El objeto Catálogo recibe como parámetro una instancia que responde a la
interfaz FábricaVehículo, es decir o bien una instancia de
FábricaVehículoElectricidad, o bien una instancia de
FábricaVehículoGasolina. Con dicha instancia, el catálogo puede crear
y manipular los vehículos sin tener que conocer las familias de vehículos y las
clases concretas de instanciación correspondientes.

31
Estructura del Patrón Fábrica de Abstracciones
1.-Diagrama de clases

2.-Participantes.
Los participantes del patrón son los siguientes:

 FábricaAbstracta (FábricaVehículo) es una interfaz que define las


firmas de los métodos que crean los distintos productos.
 FábricaConcreta1, FábricaConcreta2 (FábricaVehículoElectricidad,
FábricaVehículoGasolina) son las clases concretas que implementan los
métodos que crean los productos para cada familia de producto.

Conociendo la familia y el producto, son capaces de crear una instancia del


producto para esta familia.
32
 ProductoAbstractoA y ProductoAbstractoB (Scooter y Automóvil) son
las clases abstractas de los productos independientemente de su familia.
Las familias se introducen en las subclases concretas.
 Cliente es la clase que utiliza la interfaz de FábricaAbstracta.

3.- Colaboraciones
La clase Cliente utiliza una instancia de una de las fábricas concretas para crear
sus productos a partir de la interfaz FábricaAbstracta.

Normalmente sólo es necesario crear una instancia de cada fábrica concreta,


que puede compartirse por varios clientes.

Dominios de uso
El patrón se utiliza en los dominios siguientes:

 Un sistema que utiliza productos necesita ser independiente de la forma


en que se crean y agrupan estos productos.
 Un sistema está configurado según varias familias de productos que
pueden evolucionar.

////////////////////////////////////////////////////

El código Java correspondiente a la clase abstracta Automovil y sus subclases


aparece a continuación. Se muestra los cuatro atributos de los automóviles así
como el método mostrarCaracteristicas que permite visualizarlas.

////////////////////////////////////////////////////

public abstract class Automovil


{
protected String modelo;
protected String color;
protected int potencia;
protected double espacio;

33
public Automovil(String modelo, String color, int
potencia, double espacio)
{
this.modelo = modelo;
this.color = color;
this.potencia = potencia;
this.espacio = espacio;
}

public abstract void mostrarCaracteristicas();


}
///////////////////////////////////////////////////////////////

public class AutomovilElectricidad extends Automovil


{
public AutomovilElectricidad(String modelo, String
color, int potencia, double espacio)
{
super(modelo, color, potencia, espacio);
}

public void mostrarCaracteristicas()


{
System.out.println(
"Automovil electrico de modelo: " + modelo +
" de color: " + color + " de potencia: " +
potencia + " de espacio: " + espacio);
}
}

///////////////////////////////////////////////////////////////

public class AutomovilGasolina extends Automovil


{
public AutomovilGasolina(String modelo, String
color, int potencia, double espacio)
{
super(modelo, color, potencia, espacio);
}

public void mostrarCaracteristicas()


{
System.out.println(
"Automovil de gasolina de modelo: " + modelo +
" de color: " + color + " de potencia: " +
potencia + " de espacio: " + espacio);
}
}
///////////////////////////////////////////////////////////////

El código Java correspondiente a la clase abstracta Scooter y sus subclases


aparece a continuación. Parecido al código de los automóviles, salvo por el
atributo espacio que no se considera para las scooters.

///////////////////////////////////////////////////////////////

34
using System;

public abstract class Scooter


{
protected String modelo;
protected String color;
protected int potencia;

public Scooter(String modelo, String color, int


potencia)
{
this.modelo = modelo;
this.color = color;
this.potencia = potencia;
}
public abstract void mostrarCaracteristicas();
}

///////////////////////////////////////////////////////////////

public class ScooterElectricidad extends Scooter


{
public ScooterElectricidad(String modelo, String color,
int potencia)
{
super(modelo, color, potencia);
}

public void mostrarCaracteristicas()


{
System.out.println("Scooter electrica de modelo: " +
modelo + " de color: " + color +
" de potencia: " + potencia);
}

///////////////////////////////////////////////////////////////

public class ScooterGasolina extends Scooter


{
public ScooterGasolina(String modelo, String color,
int potencia)
{
super(modelo, color, potencia);
}

public void mostrarCaracteristicas()


{
System.out.println("Scooter de gasolina de modelo: " +
modelo + " de color: " + color +
" de potencia: " + potencia);
}

///////////////////////////////////////////////////////////////
35
Creación de interfaces: Lla interfaz FabricaVehiculo y sus dos clases de
implementación, una para cada familia (eléctrico/gasolina).

Observe que sólo las clases de implementación utilizan las clases concretas
de los vehículos.

///////////////////////////////////////////////////////////////

public interface FabricaVehiculo


{
Automovil creaAutomovil(String modelo, String color,
int potencia, double espacio);

Scooter creaScooter(String modelo, String color, int


potencia);
}

///////////////////////////////////////////////////////////////

public class FabricaVehiculoElectricidad implements FabricaVehiculo


{
public Automovil creaAutomovil(String modelo, String
color, int potencia, double espacio)
{
return new AutomovilElectricidad(modelo, color,
potencia, espacio);
}

public Scooter creaScooter(String modelo, String


color, int potencia)
{
return new ScooterElectricidad(modelo, color,
potencia);
}
}

///////////////////////////////////////////////////////////////

public class FabricaVehiculoGasolina implements FabricaVehiculo


{
public Automovil creaAutomovil(String modelo, String
color, int potencia, double espacio)
{
return new AutomovilGasolina(modelo, color,
potencia, espacio);
}

public Scooter creaScooter(String modelo, String


color, int potencia)
{
return new ScooterGasolina(modelo, color, potencia);
}
}

36
///////////////////////////////////////////////////////////////

Finalmente, el código fuente Java del cliente de la fábrica, en el ejemplo a


saber el catálogo que es, el programa principal.

Por motivos académicos, en este código, el catálogo solicita al comienzo la


fábrica que se quiere utilizar (electricidad o gasolina).

Esta fábrica debería proporcionarse como parámetro al catálogo.


El resto del programa es totalmente independiente de la familia de objetos,
respetando el objetivo del patrón Abstract Factory.

///////////////////////////////////////////////////////////////

import java.util.*;
public class Catalogo
{
public static int nAutos = 5;
public static int nScooters = 3;

public static void main(String[] args)


{
Scanner reader = new Scanner(System.in);
FabricaVehiculo fabrica;
Automovil[] autos = new Automovil[nAutos];
Scooter[] scooters = new Scooter[nScooters];
System.out.print("Qué tipo de vehículo desea utilizar: " +
"Vehículos eléctricos (1) o a gasolina (2):");
String eleccion = reader.next();
if (eleccion.equals("1"))
{
fabrica = new FabricaVehiculoElectricidad();
}
else
{
fabrica = new FabricaVehiculoGasolina();
}
for (int i = 0; i < nAutos; i++)
autos[i] = fabrica.creaAutomovil("Estandar",
"Blanco", 6+i, 3.2);
for (int i = 0; i < nScooters; i++)
scooters[i] = fabrica.creaScooter("Clásico",
"Azul", 2+i);
for (Automovil auto: autos)
auto.mostrarCaracteristicas();

for (Scooter scooter: scooters)


scooter.mostrarCaracteristicas();
}

37
///////////////////////////////////////////////////////////////
Ejecutamos en Eclipse

///////////////////////////////////////////////////////////////

Qué tipo de vehículo desea utilizar: Vehículos eléctricos (1) o a gasolina (2):1
Automovil electrico de modelo: Estandar de color: Blanco de potencia: 6 de espacio: 3.2
Automovil electrico de modelo: Estandar de color: Blanco de potencia: 7 de espacio: 3.2
Automovil electrico de modelo: Estandar de color: Blanco de potencia: 8 de espacio: 3.2
Automovil electrico de modelo: Estandar de color: Blanco de potencia: 9 de espacio: 3.2
Automovil electrico de modelo: Estandar de color: Blanco de potencia: 10 de espacio: 3.2
Scooter electrica de modelo: Clásico de color: Azul de potencia: 2
Scooter electrica de modelo: Clásico de color: Azul de potencia: 3
Scooter electrica de modelo: Clásico de color: Azul de potencia: 4

////////////////////////////////////////////////////////////////////

El propósito de Abstract Factory es proporcionar una interfaz para


crear familias de objetos relacionados, sin especificar clases concretas.

Una jerarquía que encapsula: muchas "plataformas" posibles y la


construcción de un conjunto de "productos".

El operador new puede traer problemas.

38
Imagen de Resumen tomado de (Bustacara, 2019)

Ejercicios propuestos.
1.-Un ejemplo de Abstract Factory, se encuentra en un equipo de estampado de
chapa metálica utilizado en la fabricación de automóviles japoneses. El equipo
de estampado es una fábrica abstracta que crea partes de carrocería. La misma
maquinaria se utiliza para sellar puertas de la derecha, puertas de la izquierda,
guardabarros delanteros derechos, guardabarros delanteros izquierdos,
capuchas, etc. para diferentes modelos de automóviles. Mediante el uso de
rodillos para cambiar las matrices de estampado, las clases concretas
producidas por la maquinaria se pueden cambiar en tres minutos
(SourceMaking, 2019).

39
Estampado de chapa metálica tomado de (SourceMaking, 2019)

Decida si la "independencia de la plataforma" y los servicios de creación son la


fuente actual de problemas.

Defina una interfaz de fábrica que conste de un método de fábrica por producto.

Defina una clase derivada de fábrica para cada plataforma que encapsule todas
las referencias al operador new

El cliente debe retirar todas las referencias new y utilizar los métodos de fábrica
para crear los objetos del producto.

2.- Un cliente necesita una aplicación que le permita gestionar 2 tipos de


dispositivos, para ello encomienda a un diseñador de software diseñe la
Factoría de dispositivos POS basados en Java, cuyas operaciones principales
son NuevoCajonCaja() y NuevoDispensadorMonedas(), quien tiene una
relación de realización con una factoría de dispositivos IBM y otra factoría de
dispositivos NCR.
40
2a-- Diseñar con UML el patrón correspondiente, usar relaciones,
multiplicidad, clases, interfaces, u otro artefacto…

2b—Implementar en java dicho diseño a fin de que el módulo de software


permita realizar por ejemplo dispensación con la marca solicitada (IBM o NCR)

41
Sesión 4

El Patrón Builder
El objetivo del patrón Builder es abstraer la construcción de objetos complejos
de su implementación, de modo que un cliente pueda crear objetos complejos
sin tener que preocuparse de las diferencias en su implantación (Debrauwer,
2013).

Así podemos decir que el patrón Builder se aplica si se necesita crear objetos
complejos compuestos de varias partes independientes.

Estructura del Patrón Builder


1.-Diagrama de clases

42
Ejemplo de aplicación.

Patrón Builder, tomado de (Debrauwer, 2013).

Durante la compra de un vehículo, el vendedor crea todo un conjunto de


documentos que contienen en especial la solicitud de pedido y la solicitud de
matrícula del cliente. Es posible construir estos documentos en formato HTML
o en formato PDF según la elección del cliente. En el primer caso, el cliente le
provee una instancia de la clase ConstructorDocumentaciónVehículoHtml y
en el segundo caso, una instancia de la clase
ConstructorDocumentaciónVehículoPdf.

43
El vendedor realiza, a continuación, la solicitud de creación de cada
documento mediante esta instancia. De este modo el vendedor genera la
documentación con ayuda de los métodos construyeSolicitudPedido y
construyeSolicitudMatriculación.

El diagrama de clases muestra la jerarquía entre las clases


ConstructorDocumentaciónVehículo y Documentación. El vendedor puede
crear las solicitudes de pedido y las solicitudes de matriculación sin conocer las
subclases de ConstructorDocumentaciónVehículo ni las de Documentación.

Las relaciones de dependencia entre el cliente y las subclases de


ConstructorDocumentaciónVehículo se explican por el hecho de que el cliente
crea una instancia de estas subclases.

La estructura interna de las subclases concretas de Documentación no se


muestra (entre ellas, por ejemplo, la relación de composición con la clase
Documento)

2.-Participantes
Los participantes del patrón son los siguientes:

 ConstructorAbstracto (ConstructorDocumentaciónVehículo) es la clase


que define la firma de los métodos que construyen las distintas partes del
producto así como la firma del método que permite obtener el producto,
una vez construido.
 ConstructorConcreto (ConstructorDocumentaciónVehículoHtml y
ConstructorDocumentaciónVehículoPdf) es la clase concreta que
implementa los métodos del constructor abstracto.
 Producto (Documentación) es la clase que define el producto. Puede ser
abstracta y poseer varias subclases concretas (DocumentaciónHtml y
DocumentaciónPdf) en caso de implementaciones diferentes.

44
 Director es la clase encargada de construir el producto a partir de la
interfaz del constructor abstracto.

3.- Colaboraciones
El cliente crea un constructor concreto y un director. El director construye, bajo
demanda del cliente, invocando al constructor y reenvía el resultado al cliente.

4.- Ámbito de aplicación


 Un cliente necesita construir objetos complejos sin conocer su
implementación.
 Un cliente necesita construir objetos complejos que tienen varias
representaciones o implementaciones.

45
El Patrón Factory Method
El objetivo del patrón Factory Method es proveer un método abstracto de
creación de un objeto delegando en las subclases concretas su creación efectiva.

O sea, podemos utilizar este patrón cuando definamos una clase a partir de la
que se crearán objetos pero sin saber de qué tipo son, siendo otras subclases las
encargadas de decidirlo. ¡Interesante, verdad!.

Estructura del Patrón Factory Method


1.-Diagrama de clases

46
Ejemplo de aplicación

Patrón Factory Method, tomado de (Debrauwer, 2013).

Vamos a ubicarnos en el caso de los clientes y sus pedidos. La clase Cliente


implementa el método protegido creaPedido que debe crear el pedido. Ciertos
clientes solicitan un vehículo pagando al contado y otros clientes utilizan un
crédito. En función del cliente, el método creaPedido debe crear una instancia
de la clase PedidoContado o una instancia de la clase PedidoCrédito. Para
realizar estas alternativas, el método creaPedido es abstracto.

Ambos tipos de cliente se distinguen mediante dos subclases


concretas de la clase abstracta Cliente:

47
La clase concreta ClienteContado cuyo método creaPedido crea una instancia
de la clase PedidoContado.

La clase concreta ClienteCrédito cuyo método creaPedido crea una instancia
de la clase PedidoCrédito.

En el ejemplo mostrado el método creaPedido es el método


de fabricación.

2.- Participantes
Los participantes del patrón en el ejemplo mostrado son los siguientes:

CreadorAbstracto (Cliente) es una clase abstracta que implementa la firma


del método de fabricación y los métodos que invocan al método de fabricación.
CreadorConcreto (ClienteContado, ClienteCrédito) es una clase concreta
que implementa el método de fabricación. Pueden existir varios creadores
concretos.
Producto (Pedido) es una clase abstracta que describe las propiedades
comunes de los productos.

ProductoConcreto (PedidoContado, PedidoCrédito) es una clase concreta


que describe completamente un producto.

3.- Colaboraciones
Los métodos concretos de la clase CreadorAbstracto se basan en la
implementación del método de fabricación en las subclases. Esta
implementación crea una instancia de la subclase adecuada de Producto.

4.- Ámbito de aplicación


 Una clase que sólo conoce los objetos con los que tiene relaciones.
 Una clase quiere transmitir a sus subclases las elecciones de
instanciación aprovechando un mecanismo de polimorfismo.

48
Práctica de Laboratorio:Código Java para el Patrón Builder
////////////////////////////////////////////////////////////

Código Java correspondiente a la clase abstracta Documentacion y sus subclases

////////////////////////////////////////////////////////////

import java.util.*;

public abstract class Documentacion


{
protected List<String> contenido = new ArrayList<String>();

public abstract void agregaDocumento(String documento);


public abstract void imprime();
}

////////////////////////////////////////////////////////////

public class DocumentacionHtml extends Documentacion


{
public void agregaDocumento(String documento)
{
if (documento.startsWith("<HTML>"))
contenido.add(documento);
}

public void imprime()


{
System.out.println("Documentación en formato HTML");
for (String s: contenido)
System.out.println(s);
}
}
////////////////////////////////////////////////////////////

public class DocumentacionPdf extends Documentacion


{
public void agregaDocumento(String documento)
{
if (documento.startsWith("<PDF>"))
contenido.add(documento);
}

public void imprime()


{
System.out.println("Documentación en formato PDF");
for (String s: contenido)
System.out.println(s);
}
}
////////////////////////////////////////////////////////////

49
A continuación, las clases que generan Documentacion

////////////////////////////////////////////////////////////

public abstract class ConstructorDocumentacionVehiculo


{
protected Documentacion documentacion;

public abstract void construyeSolicitudPedido(String nombreCliente);

public abstract void construyeSolicitudMatriculacion


(String nombreSolicitante);

public Documentacion resultado()


{
return documentacion;
}
}

////////////////////////////////////////////////////////////

public class ConstructorDocumentacionVehiculoHtml extends


ConstructorDocumentacionVehiculo
{
public ConstructorDocumentacionVehiculoHtml()
{
documentacion = new DocumentacionHtml();
}

public void construyeSolicitudPedido(String


nombreCliente)
{
String documento;
documento = "<HTML>Solicitud de pedido Cliente: " +
nombreCliente + "</HTML>";
documentacion.agregaDocumento(documento);
}

public void construyeSolicitudMatriculacion


(String nombreSolicitante)
{
String documento;
documento =
"<HTML>Solicitud de matriculación Solicitante: " +
nombreSolicitante + "</HTML>";
documentacion.agregaDocumento(documento);
}
}

////////////////////////////////////////////////////////////

public class ConstructorDocumentacionVehiculoPdf extends


ConstructorDocumentacionVehiculo
{
public ConstructorDocumentacionVehiculoPdf()
{
documentacion = new DocumentacionPdf();

50
}

public void construyeSolicitudPedido(String


nombreCliente)
{
String documento;
documento = "<PDF>Solicitud de pedido Cliente: " +
nombreCliente + "</PDF>";
documentacion.agregaDocumento(documento);
}

public void construyeSolicitudMatriculacion


(String nombreSolicitante)
{
String documento;
documento = "<PDF>Solicitud de matriculación Solicitante: " +
nombreSolicitante + "</PDF>";
documentacion.agregaDocumento(documento);
}
}

////////////////////////////////////////////////////////////

Respecto a la clase Vendedor: Su constructor recibe como parámetro una


instancia de ConstructorDocumentacionVehiculo. El método construye() toma
como parámetros la información del cliente.

////////////////////////////////////////////////////////////

public class Vendedor


{
protected ConstructorDocumentacionVehiculo constructor;

public Vendedor(ConstructorDocumentacionVehiculo constructor)


{
this.constructor = constructor;
}

public Documentacion construye(String nombreCliente,String


nombreSolicitante)
{
constructor.construyeSolicitudPedido(nombreCliente);
constructor.construyeSolicitudMatriculacion(nombreSolicitante);
Documentacion documentacion = constructor.resultado();
return documentacion;
}
}
////////////////////////////////////////////////////////////

Código Java del cliente del constructor. La clase


ClienteVehiculo constituye el programa principal. Este programa

51
solicita al usuario el constructor que debe utilizar, y se lo proporciona a
continuación al vendedor.

////////////////////////////////////////////////////////////

import java.util.*;
public class ClienteVehiculo
{
public static void main(String[] args)
{
Scanner reader = new Scanner(System.in);
ConstructorDocumentacionVehiculo constructor;
System.out.print("Desea generar " +
"documentacion HTML (1) o PDF (2):");
String seleccion = reader.next();
if (seleccion.equals("1"))
{
constructor = new ConstructorDocumentacionVehiculoHtml();
}
else
{
constructor = new ConstructorDocumentacionVehiculoPdf();
}
Vendedor vendedor = new Vendedor(constructor);
Documentacion documentacion = vendedor.construye("Maluma","Ozuna");
documentacion.imprime();
}
}
////////////////////////////////////////////////////////////

Ejecución:

Desea generar documentación HTML (1) o PDF (2):2


Documentación en formato PDF
<PDF>Solicitud de pedido Cliente: Maluma</PDF>
<PDF>Solicitud de matriculación Solicitante: Ozuna</PDF>

////////////////////////////////////////////////////////////

52
Práctica de Laboratorio:Código para el Patrón Factory Method
//////////////////////////////////////////////////

Se presenta el código javo de la clase abstracta Pedido y de sus dos subclases


concretas. El importe de pedido se pasa como parámetro al constructor de la
clase. Si la validación de un pedido al contado es sistemática, tenemos la
posibilidad de escoger, para nuestro ejemplo, aceptar únicamente aquellos
pedidos provistos de un crédito cuyo valor se sitúe entre 5000 y 8000.

/////////////////////////////////////////////////

public abstract class Pedido


{
protected double importe;

public Pedido(double importe)


{
this.importe = importe;
}

public abstract boolean valida();

public abstract void paga();


}
/////////////////////////////////////////////////

public class PedidoContado extends Pedido


{
public PedidoContado(double importe)
{
super(importe);
}
public void paga()
{
System.out.println(
"El pago al CONTADO del pedido por un importe de: " +
importe + " se ha completado con éxito.");
}

public boolean valida()


{
return true;
}
}

53
/////////////////////////////////////////////////

package principal;
public class PedidoCredito extends Pedido
{
public PedidoCredito(double importe)
{
super(importe);
}

public void paga()


{
System.out.println(
"El pago a CRÉDITO del pedido por un importe de: " +
importe + " se ha completado con éxito.");
}

@Override
public boolean valida()
{
return (importe >= 5000.0) && (importe <= 12000.0);
}
}

/////////////////////////////////////////////////

Ahora se muestra el código de la clase abstracta Cliente y de sus subclases


concretas. Un cliente puede realizar muchos pedidos, y sólo los que se validan
se agregan a la lista.

/////////////////////////////////////////////////

import java.util.*;
public abstract class Cliente
{
protected List<Pedido> pedidos =
new ArrayList<Pedido>();

protected abstract Pedido creaPedido(double importe);

public void nuevoPedido(double importe)


{
Pedido pedido = this.creaPedido(importe);
if (pedido.valida())
{
pedido.paga();
pedidos.add(pedido);
}
}
}

/////////////////////////////////////////////////

54
public class ClienteContado extends Cliente
{
protected Pedido creaPedido(double importe)
{
return new PedidoContado(importe);
}
}
/////////////////////////////////////////////////

public class ClienteCredito extends Cliente


{
protected Pedido creaPedido(double importe)
{
return new PedidoCredito(importe);
}
}

/////////////////////////////////////////////////

La clase Usuario muestra hace uso del patrón Factory Method.

/////////////////////////////////////////////////

package principal;
public class Usuario
{
public static void main(String[] args)

{
Cliente cliente;
cliente = new ClienteContado();
cliente.nuevoPedido(6000.0);
cliente.nuevoPedido(9000.0);
cliente = new ClienteCredito();
cliente.nuevoPedido(6000.0);
cliente.nuevoPedido(9000.0);
}
}

/////////////////////////////////////////////////

Observar que mientras el nuevo pedido se encuentre dentro del rango de crédito
la operación se desarrolla con éxito, fuera del rango no.

55
Sesión 5

El Patrón Prototype
Este patrón se utilizará si necesitamos crear y manipular copias de otros objetos,
consiste en la creación de nuevos objetos mediante duplicación de
objetos existentes llamados prototipos que disponen de la capacidad de
clonación (informaticapc.com, 2019), (Debrauwer, 2013).

Estructura del Patrón Prototype


1.-Diagrama de clases

56
Ejemplo completo tomado de (Debrauwer, 2013).

En la compra de un vehículo, un cliente recibe una documentación


formado por un número concreto de documentos tales como el certificado de
cesión, la solicitud de matriculación y/o incluso la orden de pedido. Existen
otros tipos de documentos que pueden incluirse o excluirse a esta
documentación en función de las necesidades de gestión o de cambios de
reglamentación. Así se tiene una clase Documentación cuyas instancias son

57
documentaciones compuestas por diversos documentos obligatorios. Para cada
tipo de documento, se incluye su clase correspondiente.

Luego se crea un modelo de documentación que consiste en una instancia


particular de la clase Documentación y que contiene los distintos documentos
necesarios, documentos en blanco. Llamamos a esta documentación
"documentación en blanco". De este modo definimos a nivel de las instancias,
y no a nivel de las clases, el contenido preciso de la documentación que debe
recibir un cliente. Incluir o excluir un documento en la documentación en
blanco no supone ninguna modificación en su clase. Una vez presentada la
documentación en blanco, recurrimos al proceso de clonación para crear las
nuevas documentaciones. Cada nueva documentación se crea duplicando todos
los documentos de la documentación en blanco.

El Patrón Prototype usa esta técnica basada en objetos que poseen la capacidad
de clonación y los documentos constituyen los distintos prototipos.

La clase Documento es una clase abstracta conocida por la clase


Documentación. Sus subclases corresponden a los distintos tipos de
documento. Incluyen el método duplica que permite clonar una instancia
existente para obtener una nueva.

La clase Documentación también es abstracta. Posee dos subclases concretas:


La clase DocumentaciónEnBlanco, que posee una única instancia que
contiene todos los documentos necesarios (documentos en blanco). Esta
instancia se manipula mediante los métodos incluye y excluye.

La clase DocumentaciónCliente, cuyo conjunto de documentos se crea


solicitando a la única instancia de la clase DocumentaciónEnBlanco la lista de
documentos en blanco y agregándolos uno a uno tras haberlos clonado.

58
2. Participantes
Los participantes del patrón son los siguientes:

-Cliente (Documentación, DocumentaciónCliente, DocumentaciónEnBlanco)


es una clase compuesta por un conjunto de objetos llamados prototipos,
instancias de la clase abstracta Prototype. La clase Cliente necesita duplicar
estos prototipos sin tener por qué conocer ni la estructura interna del Prototype
ni su jerarquía de subclases.

-Prototipo (Documento) es una clase abstracta de objetos capaces de


duplicarse a sí mismos. Incluye la firma del método "duplica".

PrototipoConcreto1 y PrototipoConcreto2 (OrdenDePedido,


SolicitudMatriculación, CertificadoCesión) son las subclases concretas de
Prototipo que definen completamente un prototipo e implementan el método
duplica.

3. Colaboración
El cliente solicita a uno o varios prototipos que se dupliquen a sí mismos.

4. Ámbito de aplicación
El patrón Prototype se utiliza en los dominios siguientes:

-Un sistema de objetos debe crear instancias sin conocer la jerarquía de clases

que las describe.

-Un sistema de objetos debe crear instancias de clases dinámicamente.

-El sistema de objetos debe permanecer simple y no incluir una jerarquía


paralela de clases de fabricación.

59
El Patrón Singleton
-Se usa el patrón Singleton cuando por alguna razón se necesita que exista sólo
una instancia (un objeto) de una determinada Clase.

Dicha clase se creará de forma que tenga una propiedad estática y un


constructor privado, así como un método público estático que será el encargado
de crear la instancia (cuando no exista) y guardar una referencia a la misma en
la propiedad estática (devolviendo ésta). (informaticapc.com, 2019).

-El patrón Singleton tiene como objetivo asegurar que una clase sólo posee una
instancia y proporciona un método de clase único que devuelve esta instancia.
En ciertos casos es útil gestionar clases que posean una única instancia.

En el marco de los patrones de construcción, podemos citar el caso de una


fábrica de productos (patrón Abstract Factory) del que sólo es necesario crear
una instancia (Debrauwer, 2013).

Estructura del Patrón Singleton


1.-Diagrama de clases

60
Ejemplo de creación de una Mototaxi
//////////////////////////////////////////////////

package Singleton;

public class Mototaxi


{
private static Mototaxi instancia;

private Mototaxi() {
}
public static Mototaxi getInstancia()
{
if (instancia == null) {
instancia = new Mototaxi();
System.out.println("El objeto Mototaxi ha sido
creado");
}
else {
System.out.println("Ya existe el objeto Mototaxi");
}

return instancia;
}
}

//////////////////////////////////////////////////////////////

package Singleton;

public class Main


{
public static void main(String[] args)
{
for(int i=1; i<=7; i++)
{
System.out.print(i+".-");
Mototaxi.getInstancia();
}
}
}

////////////////////////////////////

1.-El objeto Mototaxi ha sido creado


2.-Ya existe el objeto Mototaxi
3.-Ya existe el objeto Mototaxi
4.-Ya existe el objeto Mototaxi
5.-Ya existe el objeto Mototaxi
6.-Ya existe el objeto Mototaxi
7.-Ya existe el objeto Mototaxi

/////////////////////////////////////////////

61
En el código anterior, cuando se procesa el bucle for se llama al método
getInstancia() de la clase Mototaxi, devolviéndose siempre una misma
instancia (un sólo objeto) de dicha clase (que será creada la primera vez que se
llame a dicho método).

2. Participante
El único participante es la clase Singleton, que ofrece acceso a la instancia
única mediante el método de clase Instance.

Por otro lado, la clase Singleton posee un mecanismo que asegura que sólo
puede existir una única instancia. Este mecanismo bloquea la creación de otras
instancias.

3. Colaboración
Cada cliente de la clase Singleton accede a la instancia única mediante el
método de clase Instance. No puede crear nuevas instancias utilizando el
operador habitual de instanciación (operador new), que está bloqueado.

4- Ámbito de aplicación
El patrón se utiliza en el siguiente caso:

 Sólo debe existir una única instancia de una clase.


 Esta instancia sólo debe estar accesible mediante un método de clase.
 El uso del patrón Singleton ofrece a su vez la posibilidad de dejar de
utilizar variables globales.

62
Práctica de Laboratorio: Código Java para el Patrón Prototype
///////////////////////////////////////////////////////////////////////////////////

public abstract class Documento implements Cloneable


{
protected String contenido = new String();

public Documento duplica()


{
Documento resultado;

try
{
resultado = (Documento)this.clone();
}
catch (CloneNotSupportedException exception)
{
return null;
}
return resultado;
}

public void rellena(String informacion)


{
contenido = informacion;
}

public abstract void imprime();


public abstract void visualiza();
}

///////////////////////////////////////////////////////////////////////////////////

public class OrdenDePedido extends Documento


{
public void visualiza()
{
System.out.println("Muestra la Orden de Pedido: " +
contenido);
}

public void imprime()


{
System.out.println("Imprime la Orden de Pedido: " +
contenido);
}
}

///////////////////////////////////////////////////////////////////////////////////

public class SolicitudMatriculacion extends Documento


{
public void visualiza()
{
System.out.println(
"Muestra la Solicitud de Matriculación: " + contenido);
}

63
public void imprime()
{
System.out.println(
"Imprime la Solicitud de Matriculación: " + contenido);
}
}

///////////////////////////////////////////////////////////////////////////////////

public class CertificadoCesion extends Documento


{
public void visualiza()
{
System.out.println(
"Muestra el Certificado de Cesión: " + contenido);
}

public void imprime()


{
System.out.println(
"Imprime el Certificado de Cesión: " + contenido);
}
}

///////////////////////////////////////////////////////////////////////////////////

El código para la clase abstracta documentación es:

///////////////////////////////////////////////////////////////////////////////////

import java.util.*;
public abstract class Documentacion
{
protected List<Documento> documentos;

public List<Documento> getDocumentos()


{
return documentos;
}
}
///////////////////////////////////////////////////////////////////////////////////

El código de la subclase DocumentacionEnBlanco de Documentacion. Notar que aparece se utiliza el patrón


Singleton y que tiene como objetivo asegurar que una clase sólo posee una única instancia.

///////////////////////////////////////////////////////////////////////////////////

import java.util.*;
public class DocumentacionEnBlanco extends Documentacion
{
private static DocumentacionEnBlanco una_instance = null;

private DocumentacionEnBlanco()
{

64
documentos = new ArrayList<Documento>();
}

public static DocumentacionEnBlanco Instancia()


{
if (una_instance == null)
una_instance = new DocumentacionEnBlanco();
return una_instance;
}

public void incluye(Documento doc)


{
documentos.add(doc);
}

public void excluye(Documento doc)


{
documentos.remove(doc);
}
}

///////////////////////////////////////////////////////////////////////////////////

Se presenta el código de la subclase DocumentacionCliente. Su constructor obtiene la lista de documentos de


la documentación en blanco y a continuación los duplica, los rellena y los agrega a un contenedor de la
documentación.

///////////////////////////////////////////////////////////////////////////////////

import java.util.*;
public class DocumentacionCliente extends Documentacion
{
public DocumentacionCliente(String informacion)
{
documentos = new ArrayList<Documento>();
DocumentacionEnBlanco documentacionEnBlanco = DocumentacionEnBlanco.Instancia();
List<Documento> documentosEnBlanco = documentacionEnBlanco.getDocumentos();
for (Documento documento: documentosEnBlanco)
{
Documento copiaDocumento = documento.duplica();
copiaDocumento.rellena(informacion);
documentos.add(copiaDocumento);
}
}

public void visualiza()


{
for (Documento documento: documentos)
documento.visualiza();
}

public void imprime()


{
for (Documento documento: documentos)
documento.imprime();
}
}

///////////////////////////////////////////////////////////////////////////////////

public class Usuario


{
public static void main(String[] args)

65
{
//inicializacion de la documentacion en blanco
DocumentacionEnBlanco documentacionEnBlanco =
DocumentacionEnBlanco.Instancia();
documentacionEnBlanco.incluye(new OrdenDePedido());
documentacionEnBlanco.incluye(new CertificadoCesion());
documentacionEnBlanco.incluye(new SolicitudMatriculacion());

// creacion de documentacion nueva para dos clientes


DocumentacionCliente documentacionCliente1 =
new DocumentacionCliente("Maluma");
DocumentacionCliente documentacionCliente2 =
new DocumentacionCliente("Ozuna");
documentacionCliente1.visualiza();
System.out.println("///////////////////////");
documentacionCliente1.imprime();
System.out.println("///////////////////////");
documentacionCliente2.visualiza();
System.out.println("///////////////////////");
documentacionCliente2.imprime();
}
}
////////////////////////////////resultado////////////////////////////////

Muestra la Orden de Pedido: Maluma


Muestra el Certificado de Cesión: Maluma
Muestra la Solicitud de Matriculación: Maluma
///////////////////////
Imprime la Orden de Pedido: Maluma
Imprime el Certificado de Cesión: Maluma
Imprime la Solicitud de Matriculación: Maluma
///////////////////////
Muestra la Orden de Pedido: Ozuna
Muestra el Certificado de Cesión: Ozuna
Muestra la Solicitud de Matriculación: Ozuna
///////////////////////
Imprime la Orden de Pedido: Ozuna
Imprime el Certificado de Cesión: Ozuna
Imprime la Solicitud de Matriculación: Ozuna

/////////////////////////////////////////////

66
Sesión 6

Introducción a los patrones estructurales


Objetivo:
Facilitar la independencia de la interfaz de un objeto o de un conjunto de
objetos respecto de su implementación.

Permitir que la interfaz sea independiente de la jerarquía de clases y de la


composición de los objetos.

Encapsular la composición de objetos, aumentando el nivel de abstracción del


sistema de forma similar a como los patrones de creación encapsulan la
creación de objetos, a través de interfaces.

Carácterísticas
Las interfaces son el mecanismo más usual de estos patrones.

La encapsulación de la composición no se realiza estructurando el objeto en sí


mismo sino “transfiriendo” esta estructuración a un segundo objeto.

Esta transferencia de estructuración significa que el primer objeto posee la


interfaz de cara a los clientes y administra la relación con el segundo objeto que
gestiona la composición y no tiene ninguna interfaz con los clientes externos.

Esta realización ofrece otra mejora que es la flexibilidad en la composición, la


cual puede modificarse de manera dinámica. O sea, se puede sustituir un objeto
por otro siempre que sea de la misma clase o que respete la misma interfaz. Los
patrones Composite, Decorator y Bridge son un buen ejemplo de este
mecanismo (Debrauwer, 2013).

67
Composición estática

Si se desea varias implementaciones posibles, la solución clásica consiste en diferenciarlas a nivel de las
subclases. Es el caso de uso de la herencia de una interfaz en varias clases de implementación. Esta solución
consiste en realizar una composición estática. De manera que, una vez escogida la clase de implementación de
un objeto, no es posible cambiarla.

Composición dinámica

Las secciones correspondientes a la implementación se gestionan mediante una instancia de la clase


ImplementaciónConcretaA o mediante una instancia de la clase ImplementaciónConcretaB. Esta instancia está
referenciada por el atributo implementación. Puede sustituirse fácilmente por otra instancia durante la
ejecución. Por ello, se dice que la composición es dinámica. Esta solución presenta también la ventaja de
encapsular la sección de implementación y la vuelve totalmente transparente a los clientes.

Todos los patrones de estructuración están basados en el uso de uno o varios


objetos que determinan la estructuración.

68
Patrón estructural y su función principal
PATRÓN función
Adapter: Adapta un objeto existente.
Bridge Implementa un objeto.
Composite Organiza la composición jerárquica de un objeto.
Decorator Se sustituye el objeto existente agregándole nuevas
funcionalidades.
Facade Se sustituye un conjunto de objetos existentes confiriéndoles
una interfaz unificada.
Flyweight Está destinado a la compartición y guarda un estado
independiente de los objetos que lo referencian.
Proxy Se sustituye el objeto existente otorgando un comportamiento
adaptado a necesidades de optimización o de protección.

Patrón Adapter
Este patrón permite que trabajen juntas clases con interfaces incompatibles.
Para ello, un objeto adaptador reenvía al otro objeto los datos que recibe (a
través de los métodos que implementa, definidos en una clase abstracta o
interface) tras manipularlos en caso necesario. (informaticapc.com, 2019)

Estructura del patrón adapter


Diagrama de clases

69
Patrón Bridge
Este patrón permite desacoplar una abstracción de su implementación, de
manera que ambas puedan variar de forma independiente.

Tenemos un caso: Una clase abstracta en la que se define un método que deberá
implementar cada clase que herede de ella: ¿cómo haríamos si una clase hija
necesitase implementarlo de forma que realizase acciones diferentes
dependiendo de determinadas circunstancias?

En dichos casos nos resultaría útil el patrón Bridge (puente) ya que 'desacopla
una abstracción' (un método abstracto) al permitir indicar (durante la ejecución
del programa) a una clase qué 'implementación' del mismo debe utilizar (qué
acciones ha de realizar) (informaticapc.com, 2019).

El objetivo del patrón Bridge es separar el aspecto de implementación de un


objeto de su aspecto de representación y de interfaz. De este modo, por un lado
la implementación puede encapsularse por completo y por otro lado la
implementación y la representación pueden evolucionar de manera
independiente y sin que ninguna suponga restricción alguna sobre la otra.
(Debrauwer, 2013).

Estructura del patrón Bridge


Diagrama de clases

70
Patrón Composite
Este patrón permite crear y manejar estructuras de objetos en forma de árbol,
en las que un objeto puede contener a otro(s). Las estructuras de este tipo se
componen de nodos (un objeto que a su vez contiene otros objetos) y Hojas
(objetos que no contienen otros), y que ambos comparten una misma Interface
que define métodos que deben implementar.

Ejemplo Tomado de (Gamma, Helm, Johnson, & Vlissides, 2003)

Estructura del patrón Composite


Diagrama de clases

71
Práctica de Laboratorio: Código Java para el Patrón Adapter
////////////////////////////////////////////////////////////

Se quiere ingresar o sacar cierta cantidad de soles de un cajero, de manera que


al final obtengamos un reporte de nuestro saldo en dólares.

////////////////////////////////////////////////////////////

package estructurales.adapter.adapter01;

public interface IAdaptador


{
public abstract void sacarSoles( double pesetas );
public abstract void ingresarSoles( double pesetas );
}

///////package estructurales.adapter.adapter01;

public class CajaDolares


{
private double dolares = 0;

// -----------------

public CajaDolares() {
}

// -----------------

public double getTotalDolares()


{
return this.dolares;
}

// -----------------

public void sacarDolares( double dolares )


{
this.dolares -= dolares;
}

// -----------------

public void ingresarDolares( double dolares )


{
this.dolares += dolares;
}
}

/////////////////////////////////////////////////////

package estructurales.adapter.adapter01;

72
public class Adaptador implements IAdaptador
{
CajaDolares cajaDolares = new CajaDolares();

// ------------------

public Adaptador() {
}

// ------------------

public double getSaldo()


{
return this.cajaDolares.getTotalDolares();
}

// ------------------

@Override
public void sacarSoles( double soles )
{
double dolares = soles / 3.359865432;
cajaDolares.sacarDolares( dolares );
}

// ------------------

@Override
public void ingresarSoles( double soles )
{
double dolares = soles / 3.359865432;
cajaDolares.ingresarDolares( dolares );
}
}

////////////////////////////////////////////////////////////

package estructurales.adapter.adapter01;

public class Main


{
public static void main(String[] args)
{
Adaptador conversor = new Adaptador();

conversor.ingresarSoles( 1000 );
conversor.ingresarSoles( 9000 );
conversor.ingresarSoles( 15000 );

System.out.println( "Total Dolares: " + conversor.getSaldo() );


}
}

////////////////salida//////////////////////////

Total Dolares: 7440.774193482639

////////////////////////////////////////////////////////////

73
Práctica de Laboratorio: Código Java para el Patrón Bridge
////////////////////////////////////////////////////////////

Se desea preparar un alimento de entrada, específicamente un ceviche, pero se


desconoce con qué tipo de pescado preparar, para ello se debe usar el patrón
bridge quien a través de un implementador nos presente dos opciones de
preparado ( ceviche de pescado fresco y ceviche de pescado salpreso)

////////////////////////////////////////////////////////////

package estructurales.bridge.bridge01;

public interface IElaborar


{
public void procesar();
}

////////////////////////////////////////////////////////////

package estructurales.bridge.bridge01;

public class Salpreso implements IElaborar


{
public Salpreso() {
}

// --------------------------

@Override
public void procesar()
{
// Operaciones necesarias
// ...

System.out.println("\tCeviche preparado con Pescado Salpreso");


}
}

////////////////////////////////////////////////////////////

package estructurales.bridge.bridge01;

public class Pescadofresco implements IElaborar


{
public Pescadofresco() {
}

// --------------------------

@Override
public void procesar()
{
74
// Operaciones necesarias
// ...

System.out.println("\tCeviche preparado con Pescado Fresco");


}
}

////////////////////////////////////////////////////////////

package estructurales.bridge.bridge01;

public abstract class ElaborarAlimentoEntrada


{
// Referencia al Implementador
IElaborar implementador;

String nombre;

// --------------------------

public IElaborar getImplementador()


{
return this.implementador;
}

// --------------------------

public void setImplementador( IElaborar implementador )


{
this.implementador = implementador;
}

// --------------------------

// Método a implementar por las clases que hereden


public abstract void obtener();
}

////////////////////////////////////////////////////////////

package estructurales.bridge.bridge01;

public class ElaborarAlimentoEntradaCeviche extends ElaborarAlimentoEntrada


{
public ElaborarAlimentoEntradaCeviche( IElaborar implementador )
{
this.setImplementador( implementador );
}

// ------------------------

@Override
public void obtener()
{
System.out.println("Preparando tu cevichiiiito...");

this.getImplementador().procesar();

75
}
}

////////////////////////////////////////////////////////////

package estructurales.bridge.bridge01;

public class Main


{
public static void main(String[] args)
{
// Crear un objeto de tipo 'AbstraccionRefinada' indicándole un
'ImplementadorConcreto'
ElaborarAlimentoEntrada cevichito = new ElaborarAlimentoEntradaCeviche(
new Pescadofresco() );

cevichito.obtener();

// Ahora le indicamos que use otra implementación para obtener la de


Salpreso
cevichito.setImplementador( new Salpreso() );
cevichito.obtener();
}
}

///////////////////salida/////////////////////////////

Preparando tu cevichiiiito...
Ceviche preparado con Pescado Fresco
Preparando tu cevichiiiito...
Ceviche preparado con Pescado Salpreso

////////////////////////////////////////////////////////////

76
Práctica de Laboratorio: Código Java para el Patrón Composite
////////////////////////////////////////////////////////////

Se desea gestionar un árbol de carpetas contenedoras de archivos, en las que se


pueden almacenar archivos varios, sabiendo que una carpeta puede contener
archivos y carpetas a su vez.

////////////////////////////////////////////////////////////

package estructurales.composite.composite01;

public abstract class Nodo


{
public static final int HOJA = 1;
public static final int COMPUESTO = 2;

protected String nombre = "";


protected int tipoNodo;

// ----------------------------

public String getNombre()


{
return this.nombre;
}

// ----------------------------

public void setNombre( String nombre )


{
this.nombre = nombre;
}

// ----------------------------

public int getTipoNodo()


{
return this.tipoNodo;
}

// ----------------------------

public void setTipoNodo( int tipoNodo )


{
this.tipoNodo = tipoNodo;
}

// ----------------------------

// Método a implementar por las clases que hereden


public abstract void mostrar();
}

77
////////////////////////////////////////////////////////////

package estructurales.composite.composite01;

public class Archivo extends Nodo


{
public Archivo( String nombre )
{
this.setTipoNodo( Nodo.HOJA );
this.setNombre( nombre );
}

// ----------------------------

@Override
public void mostrar()
{
System.out.println( "Archivo: [" + this.getNombre() + "]" );
}
}

////////////////////////////////////////////////////////////

package estructurales.composite.composite01;

import java.util.ArrayList;
import java.util.List;

public class Carpeta extends Nodo


{
List<Nodo> nodos = new ArrayList<Nodo>();

// ----------------------------

public Carpeta( String nombre )


{
this.setTipoNodo( Nodo.COMPUESTO );
this.setNombre( nombre );
}

// ----------------------------

public void insertarNodo( Nodo nodo )


{
nodos.add( nodo );
}

// ----------------------------

public void eliminarNodo( Nodo nodo )


{
nodos.remove( nodo );
}

// ----------------------------

public List<Nodo> getNodos()


78
{
return nodos;
}

// ----------------------------

public Nodo getNodo( int posicion )


{
return nodos.get( posicion );
}

// ----------------------------

@Override
public void mostrar()
{
System.out.println("Listando carpeta [" + this.getNombre() + "]" );
System.out.println("=====================================");

for (Nodo nodo : nodos)


{
nodo.mostrar();
}
}
}

////////////////////////////////////////////////////////////

package estructurales.composite.composite01;

public class Main


{
public static void main(String[] args)
{
// Crear la Carpeta principal e insertar PATRONES
Carpeta F1 = new Carpeta("FOLDER_#1");

F1.insertarNodo( new Archivo("Patrón_1.txt") );


F1.insertarNodo( new Archivo("Patrón_2.txt") );
F1.insertarNodo( new Archivo("Patrón_3.txt") );

// Crear una SUBCarpeta e insertar PATRONES


Carpeta F2 = new Carpeta("FOLDER_#2");
F2.insertarNodo( new Archivo("Patrón_4.txt") );
F2.insertarNodo( new Archivo("Patrón_5.txt") );

// Insertar la SUBSCarpeta dentro de la principal


F1.insertarNodo( F2 );

// Insertar otro PATRON dentro de la Carpeta principal


F1.insertarNodo( new Archivo("Patrón_6.txt") );

F1.mostrar();

System.out.println("--------------------");

// Eliminamos la subcarpeta (junto con su contenido)


F1.eliminarNodo( F2 );
79
F1.mostrar();
}
}

////////////////////////salida///////////////////////////

Listando carpeta [FOLDER_#1]


=====================================
Archivo: [Patrón_1.txt]
Archivo: [Patrón_2.txt]
Archivo: [Patrón_3.txt]
Listando carpeta [FOLDER_#2]
=====================================
Archivo: [Patrón_4.txt]
Archivo: [Patrón_5.txt]
Archivo: [Patrón_6.txt]
--------------------
Listando carpeta [FOLDER_#1]
=====================================
Archivo: [Patrón_1.txt]
Archivo: [Patrón_2.txt]
Archivo: [Patrón_3.txt]
Archivo: [Patrón_6.txt]

////////////////////////////////////////////////////////////

80

También podría gustarte