Elisir - Comportamenti
I comportamenti in Elixir (e Erlang) sono un modo per separare e astrarre la parte generica di un componente (che diventa il modulo di comportamento) dalla parte specifica (che diventa il modulo di callback). I comportamenti forniscono un modo per:
- Definisci un insieme di funzioni che devono essere implementate da un modulo.
- Assicurati che un modulo implementi tutte le funzioni in quell'insieme.
Se devi, puoi pensare a comportamenti come le interfacce in linguaggi orientati agli oggetti come Java: un insieme di firme di funzioni che un modulo deve implementare.
Definizione di un comportamento
Consideriamo un esempio per creare il nostro comportamento e quindi utilizzare questo comportamento generico per creare un modulo. Definiremo un comportamento che saluta le persone ciao e arrivederci in diverse lingue.
defmodule GreetBehaviour do
@callback say_hello(name :: string) :: nil
@callback say_bye(name :: string) :: nil
end
Il @callbackviene utilizzata per elencare le funzioni che l'adozione dei moduli dovrà definire. Specifica inoltre il n. di argomenti, il loro tipo e i loro valori di ritorno.
Adottare un comportamento
Abbiamo definito con successo un comportamento. Ora lo adotteremo e lo implementeremo in più moduli. Creiamo due moduli che implementano questo comportamento in inglese e spagnolo.
defmodule GreetBehaviour do
@callback say_hello(name :: string) :: nil
@callback say_bye(name :: string) :: nil
end
defmodule EnglishGreet do
@behaviour GreetBehaviour
def say_hello(name), do: IO.puts("Hello " <> name)
def say_bye(name), do: IO.puts("Goodbye, " <> name)
end
defmodule SpanishGreet do
@behaviour GreetBehaviour
def say_hello(name), do: IO.puts("Hola " <> name)
def say_bye(name), do: IO.puts("Adios " <> name)
end
EnglishGreet.say_hello("Ayush")
EnglishGreet.say_bye("Ayush")
SpanishGreet.say_hello("Ayush")
SpanishGreet.say_bye("Ayush")
Quando il programma di cui sopra viene eseguito, produce il seguente risultato:
Hello Ayush
Goodbye, Ayush
Hola Ayush
Adios Ayush
Come hai già visto, adottiamo un comportamento che utilizza il @behaviourdirettiva nel modulo. Dobbiamo definire tutte le funzioni implementate nel comportamento per tutti i moduli figli . Questo può essere considerato più o meno equivalente alle interfacce nei linguaggi OOP.