# Interface - Interfaces

Primero veré bien lo que es una interface y luego de ello si paso a ver en que caso es que se define una interface vs struct para usar, ¿cual de las dos?

***

### 1. Definición de una Interfaz →

Se define usando la palabra clave `type` y puede contener uno o más métodos.

```go
type Animal interface {
    HacerSonido() string
}
```

### 2. Implementación de una interfaz →

Cualquier tipo que implemente los métodos definidos en la interfaz automáticamente se considera como una implementación de esa interfaz.

```go
type Perro struct{}

func (p Perro) HacerSonido() string {
    return "Guau"
}

type Gato struct{}

func (g Gato) HacerSonido() string {
    return "Miau"
}
```

### 3. Usando la interfaz →

```go
func HacerSonido(animal Animal) {
    fmt.Println(animal.HacerSonido())
}

func main() {
    var perro Animal = Perro{}
    var gato Animal = Gato{}
    
    HacerSonido(perro) // Salida: Guau
    HacerSonido(gato)  // Salida: Miau
}
```

### 4. **Interfaz vacía →**

La interfaz vacía (`interface{}`) puede contener cualquier tipo de dato y es útil cuando no se conoce el tipo exacto que se va a manejar.

***

## ¿En que caso se usa `struct` y en cual `interface`?

### Cuándo usar **Structs**:

1. **Datos concretos y específicos**: Si tienes un conjunto de datos bien definido y estructurado (como una persona, un coche, etc.), las estructuras son perfectas para almacenar y manejar estos datos.

* **Ejemplo**: Si estás manejando información específica, como los datos de un usuario en una aplicación.

  ```go
  type Usuario struct {
      Nombre string
      Edad   int
  }
  ```

1. **Modelado de entidades**: Las estructuras son útiles cuando tienes objetos concretos en tu sistema, y necesitas representar sus características (campos) y comportamientos (métodos).
2. **Operaciones en los datos**: Si tus métodos están diseñados para operar en los datos de una estructura específica, entonces tiene sentido usar `structs`.

### Cuándo usar **Interfaces**:

1. **Escalamientos constante:** Cuando realmente se necesite un codigo dinamico que vamos a escalar constantemente por lo tanto necesitaremos modificar, añadir constantemente nuevas funcionalidades y en este caso las interfaces son las que nos ayudarán.
2. **Polimorfismo**: Si necesitas manejar varios tipos diferentes que tienen comportamientos comunes, las interfaces son la opción correcta. Puedes crear una interfaz que defina un comportamiento común y luego tener varias implementaciones de esa interfaz.

   **Ejemplo**: Si tienes diferentes tipos de animales que pueden hacer sonidos distintos, pero quieres tratarlos de manera uniforme (como en el ejemplo anterior de `Animal`).
3. **Desacoplamiento**: Las interfaces permiten diseñar sistemas menos dependientes de implementaciones específicas. Si quieres que un sistema sea extensible y flexible, las interfaces te permiten lograrlo al definir contratos de comportamiento en lugar de detalles concretos.
4. **Abstracción de comportamiento**: Las interfaces son útiles cuando quieres definir un conjunto de comportamientos sin preocuparte de los detalles de la implementación.
5. **Sistemas extensibles**: Si necesitas permitir la adición de nuevos tipos que compartan comportamientos comunes sin modificar el código existente.

#### En resumen:

* **Structs**: Usas cuando tienes datos concretos y necesitas agrupar características en un solo lugar.
* **Interfaces**: Usas cuando quieres definir un comportamiento común entre diferentes tipos y aprovechar la flexibilidad de manejar varios tipos bajo un mismo contrato.

***

### Importante ⚠️

1. **¿Qué es una interfaz en Go?**
   1. Una interfaz es una manera de **abstraer comportamientos** comunes entre varios tipos. Sin embargo, en Go, lo que define que un tipo implemente una interfaz no es la sintaxis explícita (como en otros lenguajes con palabras clave como `implements`), sino que si un tipo implementa todos los métodos de una interfaz, entonces ese tipo **implícitamente** implementa la interfaz.

      ```go
      type Animal interface {
          HacerSonido() string
      }

      type Perro struct{}

      // Perro implementa la interfaz Animal porque tiene el método HacerSonido
      func (p Perro) HacerSonido() string {
          return "Guau"
      }
      ```

      En este caso, `Perro` **automáticamente** implementa la interfaz `Animal` porque tiene el método `HacerSonido`. No necesitas declararlo de manera explícita.
   2. **Las interfaces en Go** abstraen el comportamiento y se implementan implícitamente cuando un tipo cumple con los métodos requeridos por la interfaz.
2. **¿Cómo puedes saber si un tipo implementa una interfaz en Go?**
   1. En Go, no es necesario declarar explícitamente que un tipo implementa una interfaz. La **implementación es implícita**. Puedes saber si un tipo implementa una interfaz simplemente verificando si ese tipo tiene los **mismos métodos** definidos en la interfaz.
   2. **Para saber si un tipo implementa una interfaz**, basta con que el tipo tenga los métodos que la interfaz define.

***
