Skip to content

Commit

Permalink
Merge pull request #15 from sivanahamer/template-method
Browse files Browse the repository at this point in the history
Se realiza pull request del Template method al main
  • Loading branch information
lizethcorrales committed Jun 26, 2023
2 parents 1eb25e2 + 1ad4319 commit 7e45188
Show file tree
Hide file tree
Showing 17 changed files with 330 additions and 0 deletions.
28 changes: 28 additions & 0 deletions docs/5.patterns/comportamiento/template-method/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Template Method

<div align="center">

[![Typing SVG](https://readme-typing-svg.herokuapp.com?font=Cabin&duration=2500&pause=250&color=388CF7&background=1914FF00&center=true&vCenter=true&width=300&height=75&lines=Patr%C3%B3n+Template+Method)](https://git.io/typing-svg)

</div>

## Contenidos

1. [Definición](./content/Definicion.md)
2. [Estructura Básica](./content/Estructura.md)
3. [Problema](./content/Problema.md)
4. [Solución](./content/Solucion.md)
5. [Código UCR](./src/Cursos.py)
6. [Código Bebidas](./src/Bebida.py)
7. [Consecuencias](./content/Consecuencias.md)
8. [Implementación](./content/Implementacion.md)
9. [Relación con otros patrones](./content/Patrones_Relacionados.md)
10. [Referencias](./content/Referencias.md)

Para ver un resumen de los contenidos diríjase a la siguiente [presentación](./presentation/Template%20Method.pdf)

## About

Todo el contenido fue elaborado por:
* Gabriel González Flores. C03376. Gabriel.gonzalezflores@ucr.ac.cr
* Lizeth Corrales Cortés. C02428. Lizeth.corrales@ucr.ac.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Consecuencias
## Ventajas
* Puede permitir que los clientes anulen solo ciertas partes de un algoritmo grande, de modo que se vean menos afectados por los cambios que ocurren en otras partes del algoritmo.
* Puede extraer el código duplicado en una superclase.
* Cumple el principio DRY al evitar la duplicación de código.

(Shvets, A, 2019, p.392)

## Desventajas
* Algunos clientes pueden estar limitados por el esqueleto proporcionado por un algoritmo.
* Puede violar el principio de Liskov Substitución al suprimir la implementación de un paso predeterminada a través de una subclase.
* Los métodos plantilla tienden a ser más difíciles de mantener cuantos más pasos tienen.

(Shvets, A, 2019, p.392)


[Regresar al Readme](./../README.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Template Method
Es un patrón de diseño de comportamiento en el que se define el esqueleto o la base de un algoritmo en la superclase, pero dando la posibilidad a las subclases que creen sus propias implementaciones del algoritmo sin cambiar su estructura.

Por lo que, puede ser utilizado cuando se desea permitir a los clientes extender únicamente pasos particulares de un algoritmo, pero no todo el algoritmo o su estructura, así como cuando se poseen muchas clases con algoritmos casi idénticos, pero con algunas diferencias mínimas, de modo que se presente la necesidad de modificar todas las clases cuando el algoritmo cambie.

(Shvets, A, 2019, p.381)

[Regresar al Readme](../README.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Estructura Básica
## Elementos participantes
* Clase abstracta:
- Declara métodos que actúan como pasos de un algoritmo, así como el método de plantilla (template method) real que llama a estos métodos en un orden específico.
- Los pasos pueden declararse abstractos o tener alguna implementación predeterminada.
* Clases concretas:
- Pueden sobreescribir todos los pasos, pero no el método plantilla en sí.

(Shvets, A, 2019, p.386-387)


![Imagen Estructura básica](./../img/Estructura_Template_Method.png)

[Regresar al Readme](./../README.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Implementación
Para implementar el patrón Bridge debemos tener en cuenta las siguientes sugerencias y técnicas.

- Analizar el algoritmo que tenemos como objetivo para identificar si puede ser dividido en pasos, considerar qué pasos son comunes para todas las clases concretas y cuáles serán únicos, es decir, que deben ser implementados por la misma clase concreta.
- Crear la clase base abstracta y declarar el método plantilla dentro de esta clase base abstracta, además se debe definir dentro del método plantilla los métodos que representan los pasos dentro del algoritmo, creando de esta manera la estructura que se va a seguir.
- No está mal que todos los pasos del algoritmo sean abstractos, sin embargo, es mejor definir los pasos que pueden tener una implementación por defecto, ya que las clases concretas no deberán implementar tantos pasos.
- Para cada variación que se pueda dar dentro del algoritmo dependiendo de la situación se debe crear una nueva clase concreta, esta debe implementar los pasos abstractos y podría sobrescribir los pasos definidos de antemano.
- Analizar el algoritmo que tenemos como objetivo para identificar si puede ser dividido en pasos, considerar qué pasos son comunes para todas las clases concretas y cuáles serán únicos
- Crear la clase base abstracta y declarar el método plantilla dentro de esta clase base abstracta
- Para cada variación que se pueda dar dentro del algoritmo dependiendo de la situación, se debe crear una nueva clase concreta, esta debe implementar los pasos abstractos y podría sobrescribir los pasos definidos de antemano.

(Refactoring.guru, s.f.)

[Regresar al Readme](./../README.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Patrones Relacionados
## Strategy
* Semejante al Template Method excepto en su granularidad.
* Template Method utiliza la herencia para variar parte de un algoritmo
* Strategy utiliza la delegación para variar todo el algoritmo.
* Strategy modifica la lógica de los objetos individuales, mientras que Template Method modifica la lógica de una clase completa.

(Shvets, A, 2019, p.392)

## Factory Method
Es una especialización del Template Method. Al mismo tiempo, un método de fábrica puede servir como un paso en un método de plantilla grande.

(Shvets, A, 2019, p.392)


[Regresar al Readme](./../README.md)
30 changes: 30 additions & 0 deletions docs/5.patterns/comportamiento/template-method/content/Problema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Problema

### **¿Cuándo tiene sentido utilizar el patrón Bridge?**

El patrón Template Method tiene sentido utilizarlo cuando se desee que un cliente pueda extender únicamente algunos pasos de un algoritmo, pero siempre siguiendo una misma estructura. Por medio de este patrón se puede identificar un algoritmo monolítico y separarlo en varios pasos que se pueden extender en diferentes clases concretas.

Por otra parte, este patrón resulta útil cuando se identifican muchas clases con algoritmos casi idénticos, pero que se diferencian en muy pocos pasos, por lo tanto, cuando se convierte un algoritmo en un método plantilla, entonces se pueden encapsular dichos pasos con implementaciones similares a una superclase.


Vamos a definir dos ejemplos que ayudará a visualizar su utilidad, uno relacionado con bebidas calientes y un problema relacionado dentro de un contexto de la UCR:

### **Problema de bebidas calientes**

Digamos que se tiene un restaurante donde se sirven bebidas calientes, para preparar estas bebidas calientes se debe seguir algunos pasos que se repiten para varias bebidas calientes, pero otros pasos son completamente únicos. El problema es que para cada bebida caliente se está repitiendo mucho código y es difícil implementar una nueva bebida caliente, es por esto que se opta por el patrón de diseño Template Method.

![Ejemplo_Bebidas_Calientes_Solas](./../img/Clases_Bebidas_Calientes.png)

A continuación puede visualizar la [solución](./Solucion.md/#solución-para-problema-de-las-bebidas-calientes) al problema descrito

### **Problema dentro de un contexto de la UCR**

Dentro de Mediación Virtual, a lo largo del año, se crean muchos entornos para diferentes cursos, ya sean de ingeniería, derecho, artes, etc; como se puede suponer, al momento de crear estos entornos para los distintos cursos se tendría que generar código que puede ser diferente para cada entorno o por lo contrario, bastante similar, esto puede ser contraproducente si no se maneja correctamente, ya que se puede llegar a tener mucho código duplicado y puede llegar a complicarse, si no se tiene una estructura definida.

En este sentido, se obtendrá el siguiente resultado, en donde se define un curso de matemática, computación e inglés que no dependen de ninguna clase, pero que no poseen una estructura definida.

![Ejemplo_UCR_Sin_Bridge](./../img/Clases_Cursos_UCR.PNG)

A continuación puede visualizar la [solución](./Solucion.md/#solución-para-problema-de-la-ucr) al problema descrito

[Regresar al Readme](./../README.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Referencias

Refactoring.guru. (s.f.) Template Method. https://refactoring.guru/es/design-patterns/template-method

Shvets, A (2019) Dive Into Design Patterns.

[Regresar al Readme](./../README.md)
23 changes: 23 additions & 0 deletions docs/5.patterns/comportamiento/template-method/content/Solucion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Solución

### **Solución para problema de las bebidas calientes**
Para generar una solución más óptima al [problema de las bebidas calientes](./Problema.md/#problema-de-bebidas-calientes) podemos utilizar el patrón Template Method, ya que permitirá definir una estructura para cada bebida caliente, definiendo de antemano varios métodos que se utilizan para todas las bebidas calientes, así evitando la redundancia código y que de esta manera cada nueva bebida caliente que se quiere implementar sea más fácil de agregar y solo deberá definir pocos métodos únicos.

![Template_Bebidas_Calientes](./../img/Template_Bebidas_Calientes.png)

Para observar un ejemplo de implementación diríjase al siguiente [código](./../src/Bebida.py)

### **Solución para problema de la UCR**
Para generar una solución más óptima al [problema de la UCR](./Problema.md/#problema-dentro-de-un-contexto-de-la-ucr) podemos utilizar el patrón de comportamiento Template Method, ya que se logrará definir una estructura por medio de pasos para todos los cursos que sean creados en un futuro y evitar redundancia de código al declarar e implementar los métodos que son utilizados por todos los cursos en una clase en común.

Por lo que, siguiendo lo definido por este patrón, es necesario crear una clase abstracta denominada curso que contiene métodos como CrearCurso(), AsignarSigla(), AsignarSemestreAño(), AsignarProfes(), CrearPlantillaPlataforma(), InscribirEstudiantes() y AsignarAsistente().

El método CrearCurso() será el método plantilla que va a definir la estructura de la creación de cursos.

Con respecto a los métodos AsignarSigla(), AsignarSemestreAño(), AsignarProfes() , InscribirEstudiantes() y AsignarAsistente(), estos van a ser implementados para evitar la repetición de código, además se tiene al método CrearPlantillaCurso(), el cual será abstracto, lo cual implica que la plantilla del curso debe ser implementada cada vez que se cree una nueva clase concreta.

![Template_Cursos_UCR](./../img/Template_Cursos_UCR.PNG)

Para observar un ejemplo de implementación diríjase al siguiente [código](./../src/Cursos.py)

[Regresar al Readme](./../README.md)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
59 changes: 59 additions & 0 deletions docs/5.patterns/comportamiento/template-method/src/Bebida.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from abc import ABC, abstractmethod

class Bebida(ABC):

# Método plantilla
# Define la estructura del algoritmo
def preparar(self) -> None:
self.hervir_agua() # Paso 1
self.preparar_bebida() # Paso 2 (Abstracto)
self.verter_bebida() # Paso 3
self.agregar_ingredientes() # Paso 4 (Abstracto)

# Estos pasos ya tienen implementaciones.

def hervir_agua(self) -> None:
print("Se está hirviendo el agua...")

def verter_bebida(self) -> None:
print("Se está vertiendo la bebida...")

# Estos pasos deben ser implementados por las clases concretas.

@abstractmethod
def preparar_bebida(self) -> None:
pass

@abstractmethod
def agregar_ingredientes(self) -> None:
pass

class Café(Bebida):

def preparar_bebida(self) -> None:
print("Se está preparando el café...")

def agregar_ingredientes(self) -> None:
print("Agregando azúcar y leche al café...")


class (Bebida):

def preparar_bebida(self) -> None:
print("Se están remojando las bolsitas de té...")

def agregar_ingredientes(self) -> None:
print("Agregando miel al té...")


def client_code(bebida: Bebida) -> None:
bebida.preparar()

if __name__ == "__main__":
print("Se pidió un café")
client_code(Café())
print("\n")

print("Se pidió un té")
client_code(())
print("\n")
114 changes: 114 additions & 0 deletions docs/5.patterns/comportamiento/template-method/src/Cursos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from abc import ABC, abstractmethod

class CursoAbstracto(ABC):

def __init__(self):
self.nombreCurso = ""
self.sigla = ""
self.grupo = 0
self.cicloCurso = ""
self.profes = []
self.estudiantes = []
self.asistente = ""

# Método plantilla
# Define la estructura del algoritmo
def CrearCurso(self) -> None:
self.AsignarNombreCurso() # Paso 1
self.AsignarSigla() # Paso 2
self.AsignarGrupo() # Paso 3
self.AsignarCicloCurso() # Paso 4
self.AsignarProfes() # Paso 5
self.CrearPlantillaCurso() # Paso 6 (Abstracto)
self.InscribirEstudiantes() # Paso 7

tieneAsistente = input("¿El curso " + self.nombreCurso + " contará con un asistente? (si o no): ")
tieneAsistente = tieneAsistente.lower()

if(tieneAsistente == "si" or tieneAsistente == "sí"):
self.AsignarAsistente # Paso 8

# Estos pasos ya tienen implementaciones.

def AsignarNombreCurso(self) -> None:
self.nombreCurso = input("Ingrese el nombre del curso: ")
print("Se asignó el nombre de curso", self.nombreCurso,".\n")

def AsignarSigla(self) -> None:
self.sigla = input("Ingrese la sigla del curso: ")
print("Se asignó la sigla", self.sigla, "al curso", self.nombreCurso,".\n")

def AsignarGrupo(self) -> None:
self.grupo = input("Ingrese el grupo del curso: ")
print("Se asignó el grupo", self.grupo, "al curso", self.nombreCurso,".\n")

def AsignarCicloCurso(self) -> None:
self.cicloCurso = input("Ingrese el ciclo del curso (Ej: I 2023): ")
print("Se asignó el ciclo del curso", self.cicloCurso, "al curso", self.nombreCurso, ".\n")

def AsignarProfes(self) -> None:
listaProfes = input("Ingrese el nombre del profesor. Si son varios profesores se deben separar con comas: ")
self.profes = listaProfes.split(",")
listaProfes = ", ".join(self.profes)
print("Se asignaron los profesores\n", listaProfes, "\nal curso", self.nombreCurso, ".\n")

def InscribirEstudiantes(self) -> None:
listaEstudiantes = input("Ingrese el nombre de los estudiantes. Se deben separar con comas: ")
self.estudiantes = listaEstudiantes.split(",")
listaEstudiantes = ", ".join(self.estudiantes)
print("Se asignaron los estudiantes\n", listaEstudiantes, "\nal curso", self.nombreCurso, ".\n")

def AsignarAsistente(self) -> None:
asistente = input("Ingrese el nombre de la/el asistente: ")
self.asistente = asistente
print("Se asignó la/el asistente", self.asistente, "al curso", self.nombreCurso, ".\n")

# Este paso deben ser implementado por las clases concretas.

abstractmethod
def CrearPlantillaCurso(self) -> None:
pass

class CursoMatematica(CursoAbstracto):

def CrearPlantillaCurso(self) -> None:
print("Escogiendo Interfaz Oscura")
print("Creando sección de Información")
print("Creando sección de Tareas")
print("Creando plantilla específica para el curso", self.nombreCurso, "...\n")

class CursoComputacion(CursoAbstracto):

def CrearPlantillaCurso(self) -> None:
print("Escogiendo Interfaz Clara")
print("Creando sección de Material del Curso")
print("Creando sección de Tareas")
print("Creando sección de Proyectos")
print("Creando sección de Laboratorios")
print("Creando plantilla específica para el curso", self.nombreCurso, "...\n")

class CursoIngles(CursoAbstracto):

def CrearPlantillaCurso(self) -> None:
print("Escogiendo Interfaz Oscura")
print("Creando sección de Material del Curso")
print("Creando sección de Material Complementario")
print("Creando sección de Proyectos")
print("Creando plantilla específica para el curso", self.nombreCurso, "...\n")


def client_code(curso: CursoAbstracto) -> None:
curso.CrearCurso()

if __name__ == "__main__":
print("Creando el curso de Matemáticas")
client_code(CursoMatematica())
print("\n")

print("Creando el curso de Computación")
client_code(CursoComputacion())
print("\n")

print("Creando el curso de Inglés")
client_code(CursoIngles())
print("\n")

0 comments on commit 7e45188

Please sign in to comment.