Programación orientada a objetos en Go
Jan 05, 2023

Programación orientada a objetos en Go

🎯 Programación Orientada a Objetos en Go 🎯

🧪 Programación Orientada a Objetos (POO) 🧪 es un paradigma de programación que se centra en la abstracción de los componentes de un programa para crear una relación entre ellos 🌐. Esto se logra usando objetos 📦, y estos objetos pueden interactuar entre sí mediante mensajes 📨. Estos objetos tienen atributos (propiedades) 🏷 y comportamientos (métodos) 🛠.

📚 La Filosofía del Diseño de Go 📚

Las raíces de Go 🌱 están basadas en C y, más ampliamente, en la familia Algol. Ken Thompson 🧑‍💻 medio en broma dijo que Rob Pike, Robert Granger y él mismo se reunieron y decidieron que odiaban C++ 😠. Sea una broma o no, Go es muy diferente de C++ 🔄. Detalles sobre eso más adelante. Go se trata de la simplicidad máxima 😌. Esto lo explica de manera detallada Rob Pike en Menos es exponencialmente más.

🆚 Go frente a otros lenguajes 🆚

Go no tiene clases 🚫📚, objetos 🚫📦, excepciones 🚫❗ ni plantillas 🚫📐. Tiene recolección de basura 🗑 y concurrencia integrada ⏩. La omisión más notable en lo que respecta a la orientación a objetos es que en Go no hay una jerarquía de tipos 🚫📈. Esto contrasta con la mayoría de los lenguajes orientados a objetos como C++, Java, C#, Scala, e incluso con los lenguajes dinámicos como Python 🐍 y Ruby 💎.

🌟 Características del lenguaje orientado a objetos de Go 🌟

Go no tiene clases 🚫📚, pero tiene tipos 🔖. En particular, tiene estructuras (structs) 🏗. Las estructuras son tipos definidos por el usuario 👩‍💻👨‍💻. Los tipos de estructura (con métodos) sirven para fines similares a las clases en otros idiomas.

🏗 Estructuras (Structs) 🏗

Una estructura define el estado 📊. Aquí hay una estructura Creature 👾. Tiene un campo de nombre (Name) 🏷 y una bandera booleana llamada Real, que nos dice si es una criatura real o imaginaria 👻. Las estructuras únicamente mantienen el estado y no el comportamiento.

En Go, la programación orientada a objetos se logra mediante el uso de structs para definir el estado de los objetos 📦, y el uso de métodos para manipular el estado de los objetos 🛠. Los métodos también se pueden usar para definir comportamientos. Los métodos se definen como funciones, pero reciben un valor receiver 🔗 que les permite acceder al estado de los objetos. Esto es útil para organizar el código y mejorar la reutilización.

📖 Ejemplo 1:

type Animal struct {
    Name stringAge int
}

func (a Animal) Speak() {
    fmt.Println("Hola!")
}

func (a Animal) Walk() {
    fmt.Println("Caminando...")
}

type Dog struct {
    AnimalBreed stringSize int
}

func (d Dog) Bark() {
    fmt.Println("¡Guau!")
}

func (d Dog) Bite() {
    fmt.Println("Mordiendo...")
}

func main() {
    d := Dog{
        Animal: Animal{
            Name: "Fido",
            Age: 5,
        },
        Breed: "Dálmata",
        Size: 10,
    }
    d.Speak()
    d.Walk()
    d.Bark()
    d.Bite()
}

}Incrustación anónima 🕵️‍♂️

En Go, puedes incrustar tipos anónimos unos dentro de otros. Por ejemplo, si incrustas una estructura sin nombre, la estructura incrustada proporciona su estado (y métodos) directamente a la estructura incrustada. Veamos un ejemplo con FlyingCreature:

type FlyingCreature struct {
  Creature
  WingSpan int
}

dragon := &FlyingCreature{
    Creature{"Dragon", false},
    15,
}

fmt.Println(dragon.Name)
fmt.Println(dragon.Real)
fmt.Println(dragon.WingSpan)
Interfaces en Go 🤝

Las interfaces son el sello distintivo del soporte orientado a objetos de Go. Son tipos que declaran conjuntos de métodos, pero no tienen implementación. Las interfaces definen el comportamiento de un objeto, y cualquier objeto que implemente una interfaz debe implementar ciertos comportamientos. Por ejemplo, podemos definir una interfaz Animal:

type Animal interface {
    MakeNoise() string
    Move() string
}

type Dog struct {
    breed string
    age int
}

func (d Dog) MakeNoise() string {
    return "Woof!"
}

func (d Dog) Move() string {
    return "Run!"
}
Encapsulamiento en Go 📦

Go encapsula las cosas a nivel de paquete. Los nombres que empiezan con una letra minúscula únicamente son visibles dentro de ese paquete. Puedes ocultar cualquier cosa en un paquete privado y solamente exponer tipos específicos, interfaces y funciones de fábrica.

Herencia en Go 🌳

La herencia siempre ha sido un tema controvertido en la programación orientada a objetos. Go no tiene ningún tipo de jerarquía, pero permite compartir detalles de implementación a través de la composición. La composición mediante la incrustación de un tipo anónimo es equivalente a la herencia de la implementación.

Polimorfismo en Go 🦠

El polimorfismo es la esencia de la programación orientada a objetos: la capacidad de tratar objetos de diferentes tipos de forma uniforme siempre que se adhieran a la misma interfaz. Las interfaces de Go brindan esta capacidad de una manera muy directa e intuitiva.

En resumen, Go es un lenguaje de programación poderoso y flexible que ofrece una amplia gama de características para la programación orientada a objetos. Con su enfoque en la composición, las interfaces y la incrustación anónima, Go proporciona una experiencia única y efectiva para los desarrolladores que desean aprovechar al máximo el paradigma de la programación orientada a objetos. ¡Diviértete explorando Go! 😄

Diseño orientado a objetos: la forma de Go 🎨

En esta sección, profundizaremos en cómo se compara Go con los pilares de la programación orientada a objetos: encapsulación, herencia y polimorfismo.

Encapsulación en Go 📦 (Revisión)

Ya discutimos cómo Go encapsula cosas a nivel de paquete, pero profundicemos con un ejemplo más. Para ocultar el tipo Foo y exponer únicamente la interfaz, puedes cambiarle el nombre a foo en minúsculas y proporcionar una función NewFoo() que devuelve la interfaz pública Fooer:

type foo struct {
}

func (f foo) Foo1() {
    fmt.Println("Foo1() here")
}

func (f foo) Foo2() {
    fmt.Println("Foo2() here")
}

func (f foo) Foo3() {
    fmt.Println("Foo3() here")
}

func NewFoo() Fooer {
    return &Foo{}
}

Herencia en Go 🌳 (Revisión)

Como mencionamos antes, Go no tiene ningún tipo de jerarquía, pero permite compartir detalles de implementación a través de la composición. La composición mediante la incrustación de un tipo anónimo es equivalente a la herencia de la implementación.

Aquí hay un ejemplo en el que SuperFoo incrusta la interfaz Fooer, pero no implementa sus métodos. El compilador de Go te permitirá crear un nuevo SuperFoo y llamar a los métodos Fooer, pero obviamente fallará en tiempo de ejecución:

type SuperFooer struct {
  Fooer
}

func main() {
  s := SuperFooer{}
  s.Foo2()
}

Polimorfismo en Go 🦠 (Revisión)

El polimorfismo en Go se logra mediante interfaces. Aquí tienes un ejemplo en el que se crean múltiples creatures (¡y una door!) que implementan la interfaz Dumper y luego se llama al método Dump() para cada una:

package main

import "fmt"type Creature struct {
  Name stringReal bool
}

func Dump(c*Creature) {
  fmt.Printf("Name: '%s', Real: %t\n", c.Name, c.Real)}func (c Creature) Dump() {
  fmt.Printf("Name: '%s', Real: %t\n", c.Name, c.Real)}

type FlyingCreature struct {
  CreatureWingSpan int
}func (fc FlyingCreature) Dump() {
  fmt.Printf("Name: '%s', Real: %t, WingSpan: %d\n",
    fc.Name,
    fc.Real,
    fc.WingSpan)}

type Unicorn struct {
  Creature
}

type Dragon struct {
  FlyingCreature
}

type Pterodactyl struct {
  FlyingCreature
}

func NewPterodactyl(wingSpan int) *Pterodactyl {pet := &Pterodactyl{
    FlyingCreature{
      Creature{"Pterodactyl",true,},
      wingSpan,},}return pet
}

type Dumper interface {Dump()}

type Door struct {
  Thickness intColor     string
}func (d Door) Dump() {
  fmt.Printf("Door => Thickness: %d, Color: %s", d.Thickness, d.Color)}

func main() {creature := &Creature{"some creature",false,}uni := Unicorn{
    Creature{"Unicorn",false,},}pet1 := &Pterodactyl{
    FlyingCreature{
      Creature{"Pterodactyl",true,},5,},}pet2 := NewPterodactyl(8)door := &Door{3, "red"}Dump(creature)
  creature.Dump()
  uni.Dump()
  pet1.Dump()
  pet2.Dump()creatures := []Creature{*creature,
    uni.Creature,
    pet1.Creature,
    pet2.Creature}
  fmt.Println("Dump() through Creature embedded type")for _, creature := range creatures {
    creature.Dump()}dumpers := []Dumper{creature, uni, pet1, pet2, door}
  fmt.Println("Dump() through Dumper interface")for _, dumper := range dumpers {
    dumper.Dump()}}

Conclusión

Go es un verdadero lenguaje de programación orientado a objetos. Permite el modelado basado en objetos y promueve la mejor práctica para utilizar interfaces en vez de jerarquías de tipos concretos. Go tomó algunas decisiones sintácticas atípicas, pero en general, trabajar con tipos, métodos e interfaces se siente simple, ligero y natural.

La herencia es uno de los principales conceptos relacionados con la programación orientada a objetos, y Go lo soporta a través de la sintaxis de la composición. Esto significa que los tipos de Go pueden tener uno o más campos asociados a otros tipos. Al mismo tiempo, los métodos asociados a un tipo pueden llamar a los métodos de los tipos asociados. Esto permite una forma de herencia más simple, sin la necesidad de definir clases.

La incrustación es una forma ligeramente diferente de herencia. En Go, un tipo puede incluir otros tipos dentro de su definición. Esto permite aprovechar el comportamiento de los tipos incrustados, al tiempo que permite a los tipos tener su propio comportamiento adicional. La incrustación es una herramienta poderosa que ayuda a simplificar la programación orientada a objetos.

Las interfaces son una de las principales características de Go. Las interfaces permiten a los programadores definir un contrato para los tipos que implementan la interfaz. Esto proporciona una forma estandarizada para tratar con diferentes tipos de objetos de la misma forma. Las interfaces presentan una forma clara de definir la funcionalidad de los objetos sin necesidad de tener una jerarquía de tipos explícita.

En resumen, Go es un lenguaje de programación orientado a objetos que soporta la herencia, la incrustación y las interfaces. La herencia permite la composición de tipos y métodos, la incrustación permite la reutilización de comportamiento y las interfaces definen un contrato para los tipos que implementan la interfaz. Estas características hacen de Go un lenguaje de programación orientado a objetos moderno y poderoso.

A continuacion te dejo 10 ejercicios mas para que practiques las estructuras en Go y envies la solucion como un Pull requeste a este repositorio: Go Para Principiantes

  1. Crea una interfaz en Go llamada Shape con métodos Area() y Perimeter().
  2. Cree dos clases en Go, Rectangle y Square, que implementen la interfaz Shape.
  3. Agregue algunos atributos, como width y height, a la clase Rectangle para calcular el área y el perímetro.
  4. Agregue un atributo, side, a la clase Square para calcular el área y el perímetro.
  5. Escriba un método en la clase Rectangle que calcule el área.
  6. Escriba un método en la clase Rectangle que calcule el perímetro.
  7. Escriba un método en la clase Square que calcule el área.
  8. Escriba un método en la clase Square que calcule el perímetro.
  9. Cree una instancia de cada clase Rectangle y Square.
  10. Llame a los métodos Area() y Perimeter() para cada instancia, y verifique si los resultados son correctos.

Sebastian Gomez

Sebastian Gomez

Creador de contenido principalmente acerca de tecnología.

Leave a Reply

0 Comments

Related Posts

Categorias