¿Qué son los constructores y por qué son importantes?
Los constructores son una herramienta fundamental en la programación orientada a objetos, pues permiten instanciar clases y convertirlas en objetos. Sirven para preconfigurar o precargar ciertas propiedades esenciales para el funcionamiento y personalización de esos objetos. Ya sea en TypeScript, Python o Go, los constructores cumplen con el mismo propósito esencial: dotar de valores iniciales a las propiedades de un objeto al momento de su creación.
¿Cómo se implementan los constructores en diferentes lenguajes de programación?
En TypeScript
En TypeScript, los constructores son parte integral de las clases. Permiten definir y asignar valores a propiedades específicas al momento de crear un objeto. Por ejemplo, al implementar un constructor que reciba parámetros como name e id, estos serán asignados y utilizados cuando se instancie un nuevo objeto de la clase:
Python es igual de intuitivo en cuanto a constructores, utilizando el método especial __init__ para inicializar objetos con las propiedades deseadas:
classEmployee:def__init__(self, name,id): self.name = name
self.id=idemployee = Employee('John',1)
En Go
En Go, los constructores no existen tal cual en el lenguaje, pero se pueden emular a través de funciones personalizadas. Tal es el caso con el uso de structs, donde se puede definir una estructura y una función para crear instancias con valores iniciales:
type Employee struct{ ID int Name string Vacation bool}funcNewEmployee(id int, name string, vacation bool)*Employee {return&Employee{ ID: id, Name: name, Vacation: vacation,}}funcmain(){ e1 :=NewEmployee(1,"Alice",true) fmt.Println(e1)}
¿Cómo agregar propiedades con valores predeterminados en Go?
En Go, si no se especifican valores al inicializar un struct, el lenguaje automáticamente asigna valores por defecto: 0 para enteros, "" para strings y false para booleanos. Esto es importante de considerar para evitar errores al suponer que las propiedades son nil sin inicialización explícita.
El operador new es una alternativa válida, pero devuelve un apuntador en vez de una copia del objeto:
employee :=new(Employee)
Fórmula número cuatro: Uso de una función constructora
Crear una función constructora personalizada te ofrecerá flexibilidad y un control detallado sobre el proceso de inicialización, permitiendo ajustar el comportamiento del objeto según se necesite antes de su creación definitiva.
La utilización de funciones constructoras es especialmente valiosa en Go ya que, además de poder definir valores iniciales, te da la posibilidad de ejecutar lógica adicional previa a retornar el objeto. Esto incluye la inicialización de servicios, carga de dependencias o cualquier configuración necesaria. Aconsejamos el uso de funciones constructoras para maximizar la personalización y eficiencia del proceso de creación de objetos en Go, emulando el comportamiento de los constructores en otros lenguajes de programación orientada a objetos.
En cuanto a entender el código si es más sencillo, pero cuando necesitas hacer uso de otras funciones o hacer algún tipo de operaciones para ahí si asignar los valores al Struct, la forma del constructor es la que se requiere
Go no es 100% orientado a objectos, para hacernos una idea si Java es 95 % orientado a objetos (Recuerden que los primitivos de Java no son objectos) go es como el 50%, talvez un poco más un poco menos.
Pero almenos hasta esta clase hemos aprendido a implementar lo basico de la orientacion a objectos.
.
.
Creando una clase
Para crear una clase en go utlizamos un struct y tambien debemos utilizar la palabra reservada type al comienzo de la declaración.
// Esta es nuestra clase con dos atributostype Employee struct { id int
name string
}
.
.
Creando un constructor
Pensemos en un constructor como un representante de un gran artista el cual vela por los intereses del artista que está representando.
De igual forma el constructor de la clase vela por los intereses de la clase a la que representa, por ejemplo el constructor determina cómo es que se debe instanciar a una clase.
Si no tienes muy claro el paradigma de la programación orientada a objetos por favor para aquí y ve a este curso https://platzi.com/clases/oop/ esta buenisimo !!!
.
Aunque el profesor mostró varios ejemplos para crear un constructor a mi me gustaron estos dos.
//Forma No1: Crear directamente el objeto donde se va a utilizar .func main(){e1:=Employee{id:14,name: “Esteban”,} fmt.Printf("%v\n", e1)}
//Forma No2: Crear una función que reciba por parametro los valores que tendrá nuestro objecto , asigne los valores a sus respectivos atributos y luego devuelva una referencia en memoria del objeto creado.func NewEmployee(id int, name string)*Employee{return&Employee{id: id,//Asignando valores.name: name,}}//Nuestra función principalfunc main(){e2:=NewEmployee(23,"Miguel")//Instanciando nuestro objecto. fmt.Printf("%v\n",*e2)}
.
.
.
Creando métodos.
En simples palabras un método determina el comportamiento que tendrá un objeto, si no te suena ya sabes ve a este link https://platzi.com/clases/oop/.
.
Utilicemos los famosisimos métodos getters y setters
// Este es nuestro método set, y tenemos que indicarle que pertenece a nuestra clase Employee para ello le pasamos un puntero * que apunte a esa clase para luego poder tener acceso al atributo y asignarle el valor que nos pasen a través de este método setId.func(x *Employee)setId(i int){ x.id= i
}// Este es nuestro método get, igual que el anterior pasamos un puntero * pero en este caso vamos a retornar un valor int por ello lo indicamos en la declaracion del metodo.func(x *Employee)getId() int {return x.id}//Nuestra función principalfunc main(){e2:=NewEmployee(23,"Miguel") fmt.Printf("%v\n",*e2)idE2:= e2.getId()// recuperamos el atributo id del objecto e2 e2.setId(14)// Cambiamos el atributo id del objecto e2 fmt.Printf("%d\n", idE2) fmt.Printf("%v\n",*e2)}
Al principio cuando vi la sintaxis de go dije “por todos los servidores que es esto” pero le estoy cogiendo cariño.
También si nunca han trabajado con punteros tal vez no se sientan cómodos pero creanme los punteros de go son una ternurita comparados con C le dejo este curso: https://platzi.com/clases/1740-lenguaje-c-2019/24212-punteros/ Pero no se asusten todo es cuestion de practicar ;) .
Excelente aporte, Muchas gracias
codigo con comentarios:
package main
import"fmt"// Clase o struct empleadotype Employee struct { id int
name string
vacation bool
}// funcion/metodo constructor.func NewEmployee(id int, name string, vacation bool)*Employee{return&Employee{id: id,name: name,vacation: vacation,}}func main(){// forma numero 1.e:=Employee{} fmt.Println("%v", e)// forma numero 2.e2:=Employee{id:1,name:"Jose",} fmt.Println("%v", e2)// forma 3.e3:=new(Employee)// new devuelve un apuntador fmt.Println("%v",*e3)// con * referenciamos al valor.// forma 4.e4:=NewEmployee(4,"Laura",false) fmt.Println(*e4)}
Las propiedades por defecto son conocidas como zero values
Me parece que las formas 1, 2 y 3 son más legibles, en la forma 4 se acerca mucho a los constructores de otros lenguajes!
Otra forma para no pasar tanto parametros a la función NewEmployee es recibiendo como parametro el objeto de tipo Employee y asi no evitamos declarar los parametros uno por uno, esto es bastante enriquecedor ya que reutilizamos modelos o structs en este caso
Esta metodología es muy utilizada en otros lenguajes, yo lo utilizo mucho en C# con .NETCore y de ahí derivan los ViewModels o DTO's
Mi struct lo tengo en otra carpeta
Importo mi archivo que contiene mi struct y la funcion y le asigno una s como alias
Instancio el struct, pasamos como parametro el objeto y asignamos valores a las propiedades
"Cuando se trabajan con structs y se pasan a funciones, Go los trata como si fueran copias"
la forma 4 es la más usual de instanciar objetos
Bro, todo eso se ve en los fundamentos de go, ve al grano
¿Por qué se quiere emular el comportamiento de constructores?
Es útil cuando no conoces cuál será el valor de una variable de un struct, por lo que, al intentar emular el comportamiento de los constructores, puedes asignar un valor que el usuario haya introducido
No me queda claro porque en la funcion NewEmployee usamos punteros?
Constructores
Los constructores permiten la instanciación de una clase a un objeto, asimismo permite
definir propiedades predefinidas.
En Go podemos utilizar funciones que puedan crear structs con propiedades que nosotros
pasamos como parámetros.
Me gusto la sintaxis y el concepto de una función constructora para instanciar un struct.
Interesante los diferentes enfoques en instanciación con similitudes con Python y Java.
package main
import"fmt"type Employee struct { id int
name string
vacation bool
}func(e *Employee)SetId(id int){ e.id= id
}func(e *Employee)SetName(name string){ e.name= name
}func(e *Employee)GetId() int {return e.id}func(e *Employee)GetName() string {return e.name}func newEmployee(id int, name string, vacation bool)*Employee{return&Employee{id: id,name: name,vacation: vacation,}}func main(){e:=Employee{} fmt.Printf("%+v\n", e) e.SetId(3) e.SetName("Marco") fmt.Printf("%+v\n", e)//creamos una funcion constructorae4:=newEmployee(5,"Pepe",true) fmt.Printf("%+v\n",*e4)}
Aquí por si tienen la duda de simplemente poner el nombre para hacer referencia al valor pasado también funciona como en javascript almenos en mi versión de Golang si "go1.17".
Apuntes y código:
Los constructores permiten la instanciación de una clase a un objeto, asimismo permitedefinir propiedades predefinidas.
En Go podemos utilizar funciones que puedan crear structs con propiedades que nosotrospasamos como parámetros.
package main
import"fmt"type Employee struct { id int
name string
vacation bool
}//Emulador de constructorfunc NewEmployee(id int, name string, vacation bool)*Employee{return&Employee{id: id,name: name,vacation: vacation,}}func main(){// Forma 1e:=Employee{} fmt.Printf("%v\n", e)// Forma 2e2:=Employee{id:1,name:"Benjamin",vacation:true,} fmt.Printf("%v\n", e2)// Forma 3e3:=new(Employee) fmt.Printf("%v\n",*e3) e3.id=1 e3.name="Mateo" fmt.Printf("%v\n",*e3)// Forma 4e4:=NewEmployee(1,"Name",false) fmt.Printf("%v\n",*e4)}