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.