Menu
Coddy logo textTech

Implementazione implicita

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 26 di 107.

In molti linguaggi orientati agli oggetti, come Java o C#, devi dichiarare esplicitamente che un tipo implementa un'interfaccia usando parole chiave come implements. Go adotta un approccio diverso: l'implementazione delle interfacce è implicita.

Un tipo soddisfa un'interfaccia semplicemente implementando tutti i suoi metodi. Non è necessario dichiarare la relazione da nessuna parte. Il compilatore la deduce automaticamente.

type Writer interface {
    Write(data string) int
}

type FileWriter struct {
    Filename string
}

// FileWriter implementa implicitamente Writer
func (f FileWriter) Write(data string) int {
    fmt.Println("Writing to", f.Filename)
    return len(data)
}

Nota che non c'è una dichiarazione implements Writer su FileWriter. Poiché FileWriter ha un metodo Write(data string) int che corrisponde alla firma dell'interfaccia, soddisfa automaticamente l'interfaccia Writer.

Questo design ha una conseguenza potente: puoi definire interfacce anche dopo che i tipi esistono già. Se una libreria di terze parti ha un tipo con i metodi di cui hai bisogno, puoi creare un'interfaccia che soddisfa già senza modificare il codice originale.

func Save(w Writer, content string) {
    w.Write(content)
}

func main() {
    fw := FileWriter{Filename: "data.txt"}
    Save(fw, "Hello!")  // Works because FileWriter satisfies Writer
}

L’implementazione implicita mantiene il codice Go disaccoppiato e flessibile. I tipi non devono conoscere le interfacce in anticipo, il che rende più semplice comporre sistemi a partire da parti indipendenti.

challenge icon

Sfida

Facile

Costruiamo un sistema di consegna dei messaggi che dimostri come i tipi soddisfino implicitamente le interfacce in Go. Creerai diversi tipi di messaggero che soddisfano tutti la stessa interfaccia, senza dichiarare esplicitamente questa relazione.

Organizzerai il codice in due file:

  • messengers.go: definisci un'interfaccia Messenger con un unico metodo Send(message string) string. Poi crea due struct che soddisfino implicitamente questa interfaccia:
    • EmailMessenger con un campo Address (string)
    • SMSMessenger con un campo PhoneNumber (string)
    Ogni struct dovrebbe avere un metodo Send che restituisce una stringa che descrive la consegna. Nessuna delle due struct dovrebbe dichiarare esplicitamente di implementare Messenger: Go lo dedurrà automaticamente in base alle firme dei metodi.
  • main.go: crea una funzione chiamata DeliverMessage che accetta qualsiasi Messenger e una stringa con il messaggio, quindi restituisce il risultato della chiamata a Send. Leggi le informazioni di contatto dall'input, crea entrambi i tipi di messaggero e usa la tua funzione per consegnare i messaggi tramite ciascuno di essi.

Verranno forniti i seguenti input:

  • Riga 1: indirizzo email
  • Riga 2: numero di telefono
  • Riga 3: messaggio da inviare

I tuoi metodi Send dovrebbero restituire stringhe nei seguenti formati:

  • EmailMessenger: Email to [Address]: [message]
  • SMSMessenger: SMS to [PhoneNumber]: [message]

Per esempio, dati alice@example.com, 555-1234 e Hello!, il tuo output dovrebbe essere:

Email to alice@example.com: Hello!
SMS to 555-1234: Hello!

L'idea fondamentale è che la tua funzione DeliverMessage accetta qualsiasi Messenger e che sia EmailMessenger sia SMSMessenger soddisfano quell'interfaccia semplicemente avendo un metodo Send corrispondente. Non c'è alcuna keyword implements: l'implementazione implicita di Go gestisce tutto.

Provalo tu

package main

import (
	"bufio"
	"fmt"
	"os"
)

// TODO: Crea una funzione DeliverMessage che accetti un qualsiasi Messenger
// e una stringa di messaggio, poi restituisca il risultato della chiamata a Send

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Leggi l'indirizzo email
	email, _ := reader.ReadString('\n')
	email = email[:len(email)-1]
	
	// Leggi il numero di telefono
	phone, _ := reader.ReadString('\n')
	phone = phone[:len(phone)-1]
	
	// Leggi il messaggio
	message, _ := reader.ReadString('\n')
	if len(message) > 0 && message[len(message)-1] == '\n' {
		message = message[:len(message)-1]
	}
	
	// TODO: Crea un EmailMessenger con l'indirizzo email
	
	// TODO: Crea un SMSMessenger con il numero di telefono
	
	// TODO: Usa DeliverMessage per inviare il messaggio tramite ciascun Messenger
	// e stampa i risultati
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online