Skip to content

Instantly share code, notes, and snippets.

@zeroidentidad
Last active May 27, 2024 19:27
Show Gist options
  • Save zeroidentidad/dac5a7611c3af1b98da8dd700285551b to your computer and use it in GitHub Desktop.
Save zeroidentidad/dac5a7611c3af1b98da8dd700285551b to your computer and use it in GitHub Desktop.
GO OOP idiomatico

Aunque Go no es un lenguaje de programación orientado a objetos (OOP) en el sentido tradicional (como Java o C++), proporciona formas idiomáticas de manejar conceptos comunes de OOP como encapsulación, herencia y polimorfismo. Esta es una guía básica para aplicar principios de OOP en Go de manera idiomática:

1. Encapsulación

En Go, la encapsulación se logra utilizando la visibilidad basada en el caso de la primera letra. Los identificadores que comienzan con una letra mayúscula son exportados (públicos), mientras que los que comienzan con una letra minúscula son no exportados (privados).

Ejemplo:

package main

import "fmt"

type Person struct {
    Name string // Exportado (público)
    age  int    // No exportado (privado)
}

func NewPerson(name string, age int) *Person {
    return &Person{Name: name, age: age}
}

func (p *Person) GetAge() int {
    return p.age
}

func (p *Person) SetAge(age int) {
    p.age = age
}

func main() {
    p := NewPerson("Alice", 30)
    fmt.Println(p.Name)    // Acceso permitido
    fmt.Println(p.GetAge()) // Acceso permitido mediante método público
}

2. Composición sobre Herencia

Go favorece la composición sobre la herencia. En lugar de crear una jerarquía de clases, se pueden combinar tipos usando estructuras anidadas (embedding).

Ejemplo:

package main

import "fmt"

type Engine struct {
    Power int
}

func (e Engine) Start() {
    fmt.Println("Engine starting with power:", e.Power)
}

type Car struct {
    Engine
    Model string
}

func main() {
    myCar := Car{
        Engine: Engine{Power: 200},
        Model:  "Tesla",
    }
    fmt.Println("Car model:", myCar.Model)
    myCar.Start() // Llamada al método embebido
}

3. Interfaces

Las interfaces en Go son implementadas de forma implícita. Cualquier tipo que implemente los métodos definidos por una interfaz se considera que implementa esa interfaz.

Ejemplo:

package main

import "fmt"

type Speaker interface {
    Speak()
}

type Dog struct{}

func (d Dog) Speak() {
    fmt.Println("Woof!")
}

type Cat struct{}

func (c Cat) Speak() {
    fmt.Println("Meow!")
}

func MakeSpeak(s Speaker) {
    s.Speak()
}

func main() {
    d := Dog{}
    c := Cat{}
    
    MakeSpeak(d)
    MakeSpeak(c)
}

4. Polimorfismo

El polimorfismo en Go se logra a través del uso de interfaces.

Ejemplo:

package main

import "fmt"

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func PrintArea(s Shape) {
    fmt.Println("Area:", s.Area())
}

func main() {
    c := Circle{Radius: 5}
    r := Rectangle{Width: 10, Height: 5}
    
    PrintArea(c)
    PrintArea(r)
}

5. Constructores

Aunque Go no tiene constructores en el sentido tradicional, es común definir funciones que inicialicen y devuelvan instancias de un tipo.

Ejemplo:

package main

import "fmt"

type Employee struct {
    Name   string
    Salary float64
}

func NewEmployee(name string, salary float64) *Employee {
    return &Employee{Name: name, Salary: salary}
}

func main() {
    e := NewEmployee("John Doe", 50000)
    fmt.Println(e)
}

6. Métodos

En Go, los métodos pueden ser definidos en cualquier tipo (no solo en estructuras). La sintaxis de los métodos es similar a la de las funciones, pero con un receptor adicional.

Ejemplo:

package main

import "fmt"

type Point struct {
    X, Y int
}

func (p Point) Add(q Point) Point {
    return Point{p.X + q.X, p.Y + q.Y}
}

func main() {
    p1 := Point{2, 3}
    p2 := Point{4, 5}
    p3 := p1.Add(p2)
    fmt.Println(p3) // Output: {6 8}
}

7. Evitando Subtipo Inheritance

En Go, se evita la herencia de subtipo utilizando interfaces y composición, promoviendo un diseño más flexible y menos acoplado.

Ejemplo:

package main

import "fmt"

type Printer interface {
    Print()
}

type TextPrinter struct {
    text string
}

func (tp TextPrinter) Print() {
    fmt.Println(tp.text)
}

type HTMLPrinter struct {
    html string
}

func (hp HTMLPrinter) Print() {
    fmt.Println(hp.html)
}

func main() {
    var p Printer
    
    p = TextPrinter{text: "Hello, World!"}
    p.Print() // Output: Hello, World!
    
    p = HTMLPrinter{html: "<h1>Hello, World!</h1>"}
    p.Print() // Output: <h1>Hello, World!</h1>
}

Recursos relacionados para aplicar:

  1. SOLID en Go guia basica: https://gist.github.com/zeroidentidad/334cd6fcd338ebeff3a5161f1a6b729e

  2. Patrones de diseño de código en Go: https://refactoring.guru/es/design-patterns/go

  3. Arquitectura limpia con Go: https://medium.com/nerd-for-tech/clean-architecture-with-golang-3fa1a1c2b6d6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment