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

Conformitatea cu interfețele

Pentru ca un tip de date să corespundă unei interfețe, trebuie să implementeze toate metodele acestei interfețe. De exemplu:

package main

import "fmt"

type Stream interface{
    read() string
    write(string)
    close()
}

func writeToStream(stream Stream, text string){
    stream.write(text)
}

func closeStream(stream Stream){
    stream.close()
}

// structură fișier
type File struct{
    text string
}

// structură dosar
type Folder struct{}

// implementarea metodelor pentru tipul *File
func (f *File) read() string{
    return f.text
}

func (f *File) write(message string){
    f.text = message
    fmt.Println("Scriere în fișierul cu textul", message)
}

func (f *File) close(){
    fmt.Println("Fișierul a fost închis")
}

// implementarea metodelor pentru tipul *Folder
func (f *Folder) close(){
    fmt.Println("Dosarul a fost închis")
}

func main() {
     
    myFile := &File{}
    myFolder := &Folder{}
     
    writeToStream(myFile, "hello world")
    closeStream(myFile)
    //closeStream(myFolder)     // Eroare: tipul *Folder nu implementează interfața Stream
    myFolder.close()            // Asta se poate
}

Aici este definită interfața Stream, care reprezintă un flux de date și definește trei metode: close, read și write. De asemenea, există două structuri, File și Folder, care reprezintă, respectiv, un fișier și un dosar. Pentru tipul *File sunt implementate toate cele trei metode ale interfeței Stream. Pentru tipul *Folder este implementată doar metoda close din interfața Stream.

Astfel, tipul *File implementează interfața Stream și corespunde acestei interfețe, în timp ce tipul *Folder nu o face. Prin urmare, acolo unde se cere un obiect de tip Stream, putem folosi un obiect de tipul *File, dar nu și de tipul *Folder.

De exemplu, în funcția closeStream(), care închide un flux, se primește un parametru de tipul Stream.

La apelarea acestei funcții, putem transmite un obiect de tip *File, care corespunde interfeței Stream:

closeStream(myFile)

Însă nu putem transmite un obiect de tipul *Folder:

closeStream(myFolder)       // Eroare: tipul *Folder nu implementează interfața Stream

Totuși, putem apela metoda close pentru obiectul *Folder, dar aceasta va fi considerată o metodă proprie, care nu are nicio legătură cu interfața Stream.

Este de menționat și faptul că, în acest caz, metodele sunt implementate pentru tipul *File, adică pointerul la obiectul File, nu pentru tipul File. Acestea sunt două tipuri diferite. Prin urmare, tipul File nu corespunde interfeței Stream. De exemplu, nu putem scrie următoarele:

myFile2 := File{}
closeStream(myFile2)        // ! Eroare: tipul File nu corespunde interfeței Stream

Implementarea mai multor interfețe

Un tip de date nu trebuie neapărat să implementeze doar metodele unei singure interfețe, pentru tipul de date se pot defini metode proprii sau pot implementa metode din alte interfețe. De exemplu:

package main

import "fmt"

type Reader interface{
    read()
}

type Writer interface{
    write(string)
}

func writeToStream(writer Writer, text string){
    writer.write(text)
}

func readFromStream(reader Reader){
    reader.read()
}

type File struct{
    text string
}

func (f *File) read(){
    fmt.Println(f.text)
}

func (f *File) write(message string){
    f.text = message
    fmt.Println("Scriere în fișierul cu textul", message)
}

func main() {
     
    myFile := &File{}
    writeToStream(myFile, "hello world")
    readFromStream(myFile)
}

În acest caz, pentru tipul *File sunt implementate metodele ambelor interfețe, Reader și Writer. Astfel, putem utiliza obiectele de tip *File ca obiecte Reader și Writer.

Interfețe înlănțuite

Unele interfețe pot conține alte interfețe.

type Reader interface{
    read()
}

type Writer interface{
    write(string)
}

type ReaderWriter interface{
    Reader
    Writer
}

În acest caz, pentru ca un tip de date să corespundă unei astfel de interfețe, trebuie să implementeze toate interfețele înlănțuite. De exemplu:

package main

import "fmt"

type Reader interface{
    read()
}

type Writer interface{
    write(string)
}

type ReaderWriter interface{
    Reader
    Writer
}

func writeToStream(writer ReaderWriter, text string){
    writer.write(text)
}

func readFromStream(reader ReaderWriter){
    reader.read()
}

type File struct{
    text string
}

func (f *File) read(){
    fmt.Println(f.text)
}

func (f *File) write(message string){
    f.text = message
    fmt.Println("Scriere în fișierul cu textul", message)
}

func main() {
     
    myFile := &File{}
    writeToStream(myFile, "hello world")
    readFromStream(myFile)
    writeToStream(myFile, "lolly bomb")
    readFromStream(myFile)
}

În acest caz, sunt definite trei interfețe. Interfața ReaderWriter conține interfețele Reader și Writer. Pentru ca structura File să corespundă interfeței ReaderWriter, aceasta trebuie să implementeze metodele read și write, adică metodele ambelor interfețe înlănțuite, ceea ce se face în acest caz.