No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Implementación final de Abstract Factory

12/30
Recursos

Aportes 21

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Pienso que pasar de interfaces a abstact factory fue demasiado rápido, tuve que hacer un curso del patron factory para poder entender esta clase de verdad. Pienso que, aunque se agradece la rapidez en los contenidos, se hace complejo cuando los temas cambian tan abruptamente

🐱‍💻 ¡Hola comunidad!,
hice un repositorio realizando el ejercicio del patrón con unas cuantas modificaciones, espero les sirva, éxitos 😄

https://github.com/juancsr/go-patterns/tree/main/abstract-factory

Buenas comunidad!

Les dejo el código de la clase con apuntes para indicar mejor lo que realiza cada parte del código.
Además he añadido una función más que nos permite obtener el canal de envío de nuestros SMS/Emails 😄

package main

import "fmt"

/*
**************************************************
Problema: Enviar notificaciones de Email y SMS.

Métodos/Formas de enviar la notificación:
- Email
- SMS

Canales/Tecnologías para enviar la notificación:
- Twilio (Para SMS)
- SES (Para Email)
**************************************************
*/

// Interfaz encargada enviar una notificación, según un método y un canal de envío.
type INotificationFactory interface {
	SendNotification()
	GetSender() ISender
}

// Interfaz que recoge el método y canal de envío.
type ISender interface {
	GetSenderMethod() string
	GetSenderChannel() string
}

/*
**********************************
	SMS
**********************************
*/
// STRUCT de SMS
type SMSNotification struct {
}

// Método de SMSNotification
func (SMSNotification) SendNotification() {
	fmt.Println("Sending Notification via SMS")
}

// Método de SMSNotification
func (SMSNotification) GetSender() ISender {
	return SMSNotificationSender{}
}

// STRUCT para el envío de notificaciones SMS
type SMSNotificationSender struct {
}

// Método de SMSNotificationSender
func (SMSNotificationSender) GetSenderMethod() string {
	return "SMS"
}

// Método de SMSNotificationSender
func (SMSNotificationSender) GetSenderChannel() string {
	return "Twilio"
}

/*
**********************************
	EMAIL
**********************************
*/
// STRUCT de Email
type EmailNotification struct {
}

// Método de EmailNotification
func (EmailNotification) SendNotification() {
	fmt.Println("Sending Notification via Email")
}

// Método de EmailNotification
func (EmailNotification) GetSender() ISender {
	return EmailNotificationSender{}
}

// STRUCT para el envío de notificaciones Email
type EmailNotificationSender struct {
}

// Método de EmailNotificationSender
func (EmailNotificationSender) GetSenderMethod() string {
	return "Email"
}

// Método de EmailNotificationSender
func (EmailNotificationSender) GetSenderChannel() string {
	return "SES"
}

/*
**********************************
	Funcionalidad
**********************************
*/
// Función que evalua el tipo de notificación que debe enviar
func getNotificationFactory(notificationType string) (INotificationFactory, error) {
	if notificationType == "SMS" {
		return &SMSNotification{}, nil
	}

	if notificationType == "Email" {
		return &EmailNotification{}, nil
	}

	return nil, fmt.Errorf("No Notification Type")
}

// Función que envía la notificación
func sendNotification(f INotificationFactory) {
	f.SendNotification()
}

// Función que escoge la forma/método por la que se enviará la notificación
func getMethod(f INotificationFactory) {
	fmt.Println(f.GetSender().GetSenderMethod())
}

// Función que escoge el canal/tecnología por la que se enviará la notificación
func getChannel(f INotificationFactory) {
	fmt.Println(f.GetSender().GetSenderChannel())
}

func main() {
	smsFactory, _ := getNotificationFactory("SMS")
	emailFactory, _ := getNotificationFactory("Email")

	getMethod(smsFactory)        // Recoge el método de Envío
	getChannel(smsFactory)       // Recoge el canal de Envío
	sendNotification(smsFactory) // Envía la notificación

	getMethod(emailFactory)        // Recoge el método de Envío
	getChannel(emailFactory)       // Recoge el canal de Envío
	sendNotification(emailFactory) // Envía la notificación
}

En este canal de youtube en español explican muy bien los patrones de diseño diferentes que hay, entre ellos el Abstract Factory. Recomendadisimo. Patrones de diseño - Bettatech🍕

No entendi ni madres

Una pequeña analogía de como funciona este patrón de diseño

😃 De pronto si tienen dudas con el “_”, es el identificador en blanco. Lo que significa que se descarta el valor que debería asignarse o en otras palabras use '’ para ignorar dicha variable.

Algunos lugares donde lo usamos:

Una función devuelve un valor y no tiene la intención de usarlo en el futuro

Quiere iterar y necesita un valor “X” que no utilizará.

Excelente la aplicación practica sobre temas tan importantes como patrones de diseños

Mala metodologia de enseñamza en esta clase y la anterior donde se explica el patron de diseño abstract factory. el profesor debio abordar el tema de otra forma. En mi opinion el profesor debio explicar el tema asi:
.
1- primero debio explicar de una forma mas clara que es un patron de diseño y para que sirve ya que aunque en las clases lo explica no lo hace de forma clara. Entiendo que el enfoque del curso no son los patrones de diseño y que la intencion era explicar ese tema de forma introductoria lo cual me parece bien pero el error es que dicha explicacion introductoria no fue clara.
.
2- el profesor debio haber usado diagramas de clases uml u otro tipo de diagrama que sirvan como guia para crear el codigo de los structs e interfaces ya que con un diagrama se puede mostrar visualmente como interactuan los structs e interfaces entre si lo cual facilita entender el tema y crear el codigo. Aunque en go no hay clases sino structs pienso que un diagrama de clases uml igual serviria para explicar mejor el tema.

Excelente clase, de mis favoritas de este curso, es muy completa y se explica muy bien la finalidad

Es muy gracioso que justo en el trabajo desarrollé un micro servicio de mensajería pero, viendo este patrón de diseño, veo que tengo muchas áreas de mejora.

Creo que Platzi no lee los comentarios 😦

Utilice switch en el getNotificationFactory, y cambie algunas cosas 😛

package main

import "fmt"

// Abstract Factory

type INotificationFactory interface {
	SendNotification()
	GetSender() ISender
}

type ISender interface {
	GetSenderMethod() string
	GetSenderChannel() string
}

// SMS Sender
type SMSNotification struct {
}

func (SMSNotification) SendNotification() {
	println("Sending SMS Notification")
}

func (SMSNotification) GetSender() ISender {
	return SMSNotificationSender{}
}

type SMSNotificationSender struct {
}

func (SMSNotificationSender) GetSenderMethod() string {
	return "SMS"
}

func (SMSNotificationSender) GetSenderChannel() string {
	return "Twilio"
}

// Email Sender
type EmailNotification struct {
}

func (EmailNotification) SendNotification() {
	println("Sending Email Notification")
}

func (EmailNotification) GetSender() ISender {
	return EmailNotificationSender{}
}

type EmailNotificationSender struct {
}

func (EmailNotificationSender) GetSenderMethod() string {
	return "Email"
}

func (EmailNotificationSender) GetSenderChannel() string {
	return "SES"
}

func getNotificationFactory(notificationType string) (INotificationFactory, error) {
	switch notificationType {
	case "SMS":
		return &SMSNotification{}, nil
	case "Email":
		return &EmailNotification{}, nil
	default:
		return nil, fmt.Errorf("notification type invalid")
	}
}

func sendNotification(f INotificationFactory) {
	f.SendNotification()
	sender := f.GetSender()
	fmt.Printf("Sender: %s, Channel: %s\n", sender.GetSenderMethod(), sender.GetSenderChannel())
}

func getMethod(f INotificationFactory) {
	fmt.Println(f.GetSender().GetSenderMethod())
}

func getChannel(f INotificationFactory) {
	fmt.Println(f.GetSender().GetSenderChannel())
}

func main() {
	smsFactory, _ := getNotificationFactory("SMS")
	emailFactory, _ := getNotificationFactory("Email")

	sendNotification(smsFactory)
	sendNotification(emailFactory)

	getMethod(smsFactory)
	getMethod(emailFactory)

	getChannel(smsFactory)
	getChannel(emailFactory)
}

Les comparto una propuesta para crear métodos donde la interface se asigna como receptor del método en lugar de pasar como argumento ```js package main import ( "fmt" "math" "reflect" ) // Definición de la interfaz figura type figura interface { CalcularArea() float64 GetProps() string } // Definición de la estructura Figura que embebe la interfaz figura type Figura struct { figura } // Método para imprimir la informacion incluyendo el área de una figura definido para la estructura Figura func (f *Figura) ImprimirInfo() { // Se imprime el tipo de la figura, sus propiedades y el área calculada fmt.Printf("%s, %s, Área: %.1f \n", reflect.TypeOf(f.figura).Elem().Name(), f.GetProps(), f.CalcularArea()) } // Definición de la estructura Circulo type Circulo struct { // Radio del círculo Radius float64 } // Método para calcular el área de un círculo func (c *Circulo) CalcularArea() float64 { return math.Pi * c.Radius * c.Radius } func (c *Circulo) GetProps() string { return fmt.Sprintf("Radio: %v", c.Radius) } // Definición de la estructura Cuadrado type Cuadrado struct { // Lado del cuadrado Side float64 } // Método para calcular el área de un cuadrado func (s *Cuadrado) CalcularArea() float64 { return s.Side * s.Side } func (s *Cuadrado) GetProps() string { return fmt.Sprintf("Lado: %v", s.Side) } // Definición de la estructura Triangulo type Triangulo struct { // Base del triángulo Base float64 // Altura del triángulo Height float64 } // Método para calcular el área de un triángulo func (t *Triangulo) CalcularArea() float64 { return 0.5 * t.Base * t.Height } func (t *Triangulo) GetProps() string { return fmt.Sprintf("Base: %v, Altura: %v", t.Base, t.Height) } func main() { // Creación de instancias de las diferentes figuras en un slice de *Figura figuras := []*Figura{ {&Circulo{Radius: 5}}, {&Cuadrado{Side: 14}}, {&Circulo{Radius: 20}}, {&Cuadrado{Side: 4}}, {&Triangulo{Base: 3, Height: 6}}, {&Triangulo{Base: 5, Height: 3}}} // Iteración sobre las figuras for _, figura := range figuras { // Llamada al método ImprimirArea de la estructura Figura que embebe la interfaz figura figura.ImprimirInfo() } } ```
Este ejmplo de aca les puede ayudar mucho a entender: <https://refactoring.guru/es/design-patterns/abstract-factory/go/example>
Considero que hay mejores maneras de implementar el Abstract Factory

Se podría manejar asi:

func sendNotifications(factories ...INotificationFactory) {
	for _, factory := range factories {
		factory.SendNotification()
	}
}```

Les comparto mi implementacion de “getNotificationFactory” que utiliza un “enum” para verificar que siempre se utilicen los valores correctos en la funcion y que el autocompletado nos ayude cuando usemos esta funcion

type NotificationType string
const (
	NotificationTypeSMS   NotificationType = "SMS"
	NotificationTypeEmail NotificationType = "EMAIL"
)

func getNotificationFactory(notificationType NotificationType) (INotificationFactory, error) {
	if notificationType == NotificationTypeSMS {
		return &SMSNotification{}, nil
	}
	if notificationType == NotificationTypeEmail {
		return &EmailNotification{}, nil
	}

	return nil, fmt.Errorf("No notification type of %s", notificationType)
}

El getNotificationFactory puede ser mejor explicado en un switch/case:

func getNotificationFactory(notificationType string) (notification INotificationFactory, err error) {
	switch notificationType {
	case "SMS":
		notification = &SMSNotification{}
	case "Email":
		notification = &EmailNotification{}
	default:
		err = fmt.Errorf("No notification type")
	}
	return
}

Interesante… Buena clase

Apuntes y código

  • Go te permite implementar muchos de los patrones de diseño que están basados en polimorfismo mediante la utilización de interfaces
package main

import "fmt"

// SMS EMAIL

type INotificationFactory interface {
	SendNotification()
	GetSender() ISender
}

type ISender interface {
	GetSenderMethod() string
	GetSenderChannel() string
}

type SMSNotification struct {
}

type SMSNotificationSender struct {
}

func (SMSNotification) SendNotification() {
	fmt.Println("Sending Notification SMS")
}

func (SMSNotification) GetSender() ISender {
	return SMSNotificationSender{}
}

func (SMSNotificationSender) GetSenderMethod() string {
	return "SMS"
}

func (SMSNotificationSender) GetSenderChannel() string {
	return "Twilio"
}

type EmailNotification struct {
}

func (EmailNotification) SendNotification() {
	fmt.Println("Sending Notification via Email")
}

type EmailNotificationSender struct {
}

func (EmailNotificationSender) GetSenderMethod() string {
	return "Email"
}

func (EmailNotificationSender) GetSenderChannel() string {
	return "SES"
}

func (EmailNotification) GetSender() ISender {
	return EmailNotificationSender{}
}

func getNotificationFactory(notificationType string) (INotificationFactory, error) {
	if notificationType == "SMS" {
		return &SMSNotification{}, nil
	}

	if notificationType == "Email" {
		return &EmailNotification{}, nil
	}

	return nil, fmt.Errorf("No Notification Type")
}

func sendNotification(f INotificationFactory) {
	f.SendNotification()
}

func getMethod(f INotificationFactory) {
	fmt.Println(f.GetSender().GetSenderMethod())
}

func main() {
	smsFactory, _ := getNotificationFactory("SMS")
	emailFactory, _ := getNotificationFactory("Email")

	sendNotification(smsFactory)
	sendNotification(emailFactory)

	getMethod(smsFactory)
	getMethod(emailFactory)
}