MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Interfețe

Introducere în interfețe

Interfețele reprezintă o abstracție a comportamentului altor tipuri. Interfețele permit definirea unor funcții care nu sunt legate de o implementare specifică. Cu alte cuvinte, interfețele definesc o funcționalitate, dar nu o implementează.

Pentru a defini o interfață, se folosește cuvântul cheie interface:

type nume_interfață interface{
    definirea_funcțiilor
}

De exemplu, o definiție simplă a unei interfețe:

type vehicle interface{
    move()
}

Această interfață se numește vehicle. Să presupunem că această interfață reprezintă un anumit mijloc de transport. Ea definește funcția move(), care nu primește niciun parametru și nu returnează nimic.

Este important să înțelegem că interfața este o abstracție, nu un tip concret, cum ar fi int, string sau structuri. De exemplu, nu putem crea direct un obiect de tipul interfeței:

var v vehicle = vehicle{}

Interfața reprezintă un fel de contract la care trebuie să se conformeze tipul de date. Pentru ca un tip de date să corespundă unei interfețe, acesta trebuie să implementeze prin metode toate funcțiile acestei interfețe. De exemplu, să definim două structuri:

package main

import "fmt"

type Vehicle interface{
    move()
}

// structura "Mașină"
type Car struct{ }

// structura "Avion"
type Aircraft struct{}

func (c Car) move(){
    fmt.Println("Mașina se deplasează")
}

func (a Aircraft) move(){
    fmt.Println("Avionul zboară")
}

func main() {
     
    var tesla Vehicle = Car{}
    var boing Vehicle = Aircraft{}
    tesla.move()
    boing.move()
}

Aici sunt definite două structuri: Car și Aircraft, care, să presupunem, reprezintă o mașină și un avion. Pentru fiecare structură este definită metoda move(), care simulează deplasarea mijlocului de transport. Această metodă move corespunde funcției move a interfeței vehicle prin tipul parametrilor și tipul valorilor returnate. Deoarece există o corespondență între metoda structurii și funcția din interfață, aceste structuri implementează implicit interfața respectivă.

În Go, interfețele se implementează implicit. Nu trebuie să specificăm în mod special că structurile implementează o anumită interfață, așa cum se întâmplă în alte limbaje de programare. Pentru a implementa o interfață unui tip de date, este suficient ca acesta să implementeze metodele definite de interfață.

Deoarece structurile Car și Aircraft implementează interfața Vehicle, putem defini variabile de acest tip de interfață, atribuindu-le obiectele structurilor:

var tesla Vehicle = Car{}
var boing Vehicle = Aircraft{}

Unde ne pot ajuta interfețele?

Interfețele permit definirea unei implementări generale fără a fi legate de un tip concret. De exemplu, să analizăm următoarea situație:

package main

import "fmt"

type Car struct{ }
type Aircraft struct{}

func (c Car) move(){
    fmt.Println("Mașina se deplasează")
}

func (a Aircraft) move(){
    fmt.Println("Avionul zboară")
}

func driveCar(c Car){
    c.move()
}

func driveAircraft(a Aircraft){
    a.move()
}

func main() {
     
    var tesla Car = Car{}
    var boing Aircraft = Aircraft{}
    driveCar(tesla)
    driveAircraft(boing)
}

Să presupunem că în acest caz sunt definite două structuri, Car și Aircraft, care reprezintă o mașină și un avion. Pentru fiecare structură este definită metoda move(), care deplasează mijlocul de transport. Sunt, de asemenea, definite două funcții, driveCar() și driveAircraft(), care primesc, respectiv, structurile Car și Aircraft și sunt destinate pentru conducerea acestor mijloace de transport.

Este evident că ambele funcții driveCar și driveAircraft sunt practic identice, ele execută aceleași acțiuni, dar pentru tipuri diferite. Ar fi util dacă am putea defini o singură funcție generală pentru tipuri diferite. Mai ales având în vedere că putem avea și mai multe mijloace de transport - bicicletă, vapor etc. Și pentru fiecare mijloc de transport ar trebui să definim o metodă proprie, ceea ce nu este foarte convenabil. Și tocmai în acest caz putem utiliza interfețele:

package main
import "fmt"

type Vehicle interface{
    move()
}

func drive(vehicle Vehicle){
    vehicle.move()
}

type Car struct{ }
type Aircraft struct{}

func (c Car) move(){
    fmt.Println("Mașina se deplasează")
}

func (a Aircraft) move(){
    fmt.Println("Avionul zboară")
}

func main() {
     
    tesla := Car{}
    boing := Aircraft{}
    drive(tesla)
    drive(boing)
}

Acum, în loc de două funcții, avem o singură funcție generală - drive(), care primește ca parametru un tip Vehicle. Deoarece ambele structuri Car și Aircraft corespund acestei interfețe, putem transmite aceste structuri în funcția drive ca argumente.