Skip to content

Instantly share code, notes, and snippets.

@zeroidentidad
Last active May 27, 2024 18:37
Show Gist options
  • Save zeroidentidad/334cd6fcd338ebeff3a5161f1a6b729e to your computer and use it in GitHub Desktop.
Save zeroidentidad/334cd6fcd338ebeff3a5161f1a6b729e to your computer and use it in GitHub Desktop.
SOLID en Go guia basica

1. Single Responsibility Principle (SRP)

Cada módulo o clase debe tener una única responsabilidad o motivo para cambiar. En Go, esto se traduce en mantener las funciones y métodos enfocados en una tarea específica.

Ejemplo:

package main

import "fmt"

// Cumple con SRP, ya que solo maneja la información del empleado
type Employee struct {
    Name   string
    Salary float64
}

// Cumple con SRP, ya que solo maneja el cálculo del salario
type SalaryCalculator struct{}

func (sc SalaryCalculator) CalculateSalary(e Employee) float64 {
    return e.Salary
}

func main() {
    e := Employee{Name: "John Doe", Salary: 50000}
    sc := SalaryCalculator{}
    fmt.Println(sc.CalculateSalary(e))
}

2. Open/Closed Principle (OCP)

Las entidades de software deben estar abiertas para la extensión, pero cerradas para la modificación. Esto significa que debes poder añadir nuevas funcionalidades sin cambiar el código existente.

Ejemplo:

package main

import "fmt"

// Cumple con OCP, ya que podemos añadir nuevas formas de pago sin modificar el código existente
type Employee struct {
    Name   string
    Salary float64
}

type PaymentMethod interface {
    Pay(e Employee) string
}

type BankTransfer struct{}

func (bt BankTransfer) Pay(e Employee) string {
    return fmt.Sprintf("Paid %f to %s via Bank Transfer", e.Salary, e.Name)
}

type PayPal struct{}

func (pp PayPal) Pay(e Employee) string {
    return fmt.Sprintf("Paid %f to %s via PayPal", e.Salary, e.Name)
}

func main() {
    e := Employee{Name: "John Doe", Salary: 50000}

    var pm PaymentMethod

    pm = BankTransfer{}
    fmt.Println(pm.Pay(e))

    pm = PayPal{}
    fmt.Println(pm.Pay(e))
}

3. Liskov Substitution Principle (LSP)

Los objetos de una clase base deben poder ser sustituidos por objetos de una clase derivada sin afectar el funcionamiento del programa.

Ejemplo:

package main

import "fmt"

// Cumple con LSP, ya que ambos tipos de empleados pueden ser usados de manera intercambiable
type Employee interface {
    GetDetails() string
}

type FullTimeEmployee struct {
    Name   string
    Salary float64
}

func (fte FullTimeEmployee) GetDetails() string {
    return fmt.Sprintf("Full-time: %s with salary %f", fte.Name, fte.Salary)
}

type PartTimeEmployee struct {
    Name   string
    HourlyRate float64
}

func (pte PartTimeEmployee) GetDetails() string {
    return fmt.Sprintf("Part-time: %s with hourly rate %f", pte.Name, pte.HourlyRate)
}

func PrintEmployeeDetails(e Employee) {
    fmt.Println(e.GetDetails())
}

func main() {
    fte := FullTimeEmployee{Name: "John Doe", Salary: 50000}
    pte := PartTimeEmployee{Name: "Jane Doe", HourlyRate: 30}

    PrintEmployeeDetails(fte)
    PrintEmployeeDetails(pte)
}

4. Interface Segregation Principle (ISP)

Los clientes no deben verse obligados a depender de interfaces que no utilizan. En Go, esto significa definir interfaces pequeñas y específicas.

Ejemplo:

package main

import "fmt"

// Cumple con ISP, ya que las interfaces son específicas y pequeñas
type Printer interface {
    Print()
}

type Scanner interface {
    Scan()
}

type MultiFunctionDevice interface {
    Printer
    Scanner
}

type MultiFunctionPrinter struct{}

func (mfp MultiFunctionPrinter) Print() {
    fmt.Println("Printing...")
}

func (mfp MultiFunctionPrinter) Scan() {
    fmt.Println("Scanning...")
}

func main() {
    var mfd MultiFunctionDevice = MultiFunctionPrinter{}
    mfd.Print()
    mfd.Scan()
}

5. Dependency Inversion Principle (DIP)

Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones. En Go, esto se logra mediante el uso de interfaces.

Ejemplo:

package main

import "fmt"

// Cumple con DIP, ya que el módulo de alto nivel depende de una abstracción (interfaces)
type Worker interface {
    Work()
}

type Developer struct{}

func (d Developer) Work() {
    fmt.Println("Writing code...")
}

type Tester struct{}

func (t Tester) Work() {
    fmt.Println("Testing code...")
}

type Project struct {
    Workers []Worker
}

func (p Project) Start() {
    for _, worker := range p.Workers {
        worker.Work()
    }
}

func main() {
    dev := Developer{}
    tester := Tester{}

    project := Project{
        Workers: []Worker{dev, tester},
    }

    project.Start()
}

Recursos de referencia extra:

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